KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > netbeans > modules > java > hints > ImportClassEnabler


1 /*
2  * The contents of this file are subject to the terms of the Common Development
3  * and Distribution License (the License). You may not use this file except in
4  * compliance with the License.
5  *
6  * You can obtain a copy of the License at http://www.netbeans.org/cddl.html
7  * or http://www.netbeans.org/cddl.txt.
8  *
9  * When distributing Covered Code, include this CDDL Header Notice in each file
10  * and include the License file at http://www.netbeans.org/cddl.txt.
11  * If applicable, add the following below the CDDL Header, with the fields
12  * enclosed by brackets [] replaced by your own identifying information:
13  * "Portions Copyrighted [year] [name of copyright owner]"
14  *
15  * The Original Software is NetBeans. The Initial Developer of the Original
16  * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
17  * Microsystems, Inc. All Rights Reserved.
18  */

19
20 package org.netbeans.modules.java.hints;
21
22 import com.sun.source.tree.CompilationUnitTree;
23 import com.sun.source.tree.MethodInvocationTree;
24 import com.sun.source.tree.Tree.Kind;
25 import com.sun.source.util.TreePath;
26 import java.io.IOException JavaDoc;
27 import java.util.ArrayList JavaDoc;
28 import java.util.Arrays JavaDoc;
29 import java.util.Collections JavaDoc;
30 import java.util.HashMap JavaDoc;
31 import java.util.HashSet JavaDoc;
32 import java.util.List JavaDoc;
33 import java.util.Map JavaDoc;
34 import java.util.Set JavaDoc;
35 import java.util.logging.Level JavaDoc;
36 import java.util.logging.Logger JavaDoc;
37 import javax.lang.model.element.TypeElement;
38 import javax.swing.text.Document JavaDoc;
39 import org.netbeans.api.java.source.CancellableTask;
40 import org.netbeans.api.java.source.CompilationInfo;
41 import org.netbeans.api.java.source.JavaSource;
42 import org.netbeans.api.java.source.JavaSource.Phase;
43 import org.netbeans.api.java.source.SourceUtils;
44 import org.netbeans.api.java.source.WorkingCopy;
45 import org.netbeans.api.lexer.Token;
46 import org.netbeans.modules.java.editor.imports.ComputeImports;
47 import org.netbeans.modules.java.hints.ImportClassEnabler.ImportCandidatesHolder;
48 import org.netbeans.modules.java.hints.JavaHintsProvider;
49 import org.netbeans.modules.java.hints.LazyHintComputation;
50 import org.netbeans.modules.java.hints.spi.ErrorRule;
51 import org.netbeans.spi.editor.hints.ChangeInfo;
52 import org.netbeans.spi.editor.hints.Fix;
53 import org.openide.ErrorManager;
54 import org.openide.filesystems.FileObject;
55 import org.openide.util.NbBundle;
56 import org.openide.util.RequestProcessor;
57
58
59 /**
60  *
61  * @author Jan Lahoda
62  */

63 public final class ImportClassEnabler implements ErrorRule<ImportCandidatesHolder> {
64     
65     static RequestProcessor WORKER = new RequestProcessor("ImportClassEnabler", 1);
66     
67     public ImportClassEnabler() {
68     }
69     
70     public Set JavaDoc<String JavaDoc> getCodes() {
71         return new HashSet JavaDoc<String JavaDoc>(Arrays.asList(
72                 "compiler.err.cant.resolve",
73                 "compiler.err.cant.resolve.location",
74                 "compiler.err.doesnt.exist",
75                 "compiler.err.not.stmt"));
76     }
77     
78     public List JavaDoc<Fix> run(final CompilationInfo info, String JavaDoc diagnosticKey, final int offset, TreePath treePath, Data<ImportCandidatesHolder> data) {
79         resume();
80         
81         int errorPosition = offset + 1; //TODO: +1 required to work OK, rethink
82

83         if (errorPosition == (-1)) {
84             JavaHintsProvider.LOG.log(Level.FINE, "ImportClassEnabler.create errorPosition=-1"); //NOI18N
85

86             return Collections.<Fix>emptyList();
87         }
88
89         TreePath path = info.getTreeUtilities().pathFor(errorPosition);
90         
91         if (path.getParentPath() != null && path.getParentPath().getLeaf().getKind() == Kind.METHOD_INVOCATION) {
92             //#86313:
93
//if the error is in the type parameter, import should be proposed:
94
MethodInvocationTree mit = (MethodInvocationTree) path.getParentPath().getLeaf();
95             
96             if (!mit.getTypeArguments().contains(path.getLeaf())) {
97                 return Collections.<Fix>emptyList();
98             }
99         }
100         
101         Token ident = JavaHintsProvider.findUnresolvedElementToken(info, offset);
102         
103         JavaHintsProvider.LOG.log(Level.FINE, "ImportClassEnabler.create ident={0}", ident); //NOI18N
104

105         if (ident == null) {
106             return Collections.<Fix>emptyList();
107         }
108         
109         FileObject file = info.getFileObject();
110         String JavaDoc simpleName = ident.text().toString();
111         Pair<List JavaDoc<String JavaDoc>, List JavaDoc<String JavaDoc>> candidates = getCandidateFQNs(info, file, simpleName, data);
112         
113         if (isCancelled()) {
114             JavaHintsProvider.LOG.log(Level.FINE, "ImportClassEnabler.cancelled."); //NOI18N
115

116             return Collections.<Fix>emptyList();
117         }
118         
119         List JavaDoc<String JavaDoc> filtered = candidates.getA();
120         List JavaDoc<String JavaDoc> unfiltered = candidates.getB();
121         List JavaDoc<Fix> fixes = new ArrayList JavaDoc<Fix>();
122         
123         if (unfiltered != null && filtered != null) {
124             //TODO: simplify when editor hints allow ordering:
125
for (String JavaDoc fqn : filtered) {
126                 fixes.add(new FixImport(file, fqn, true));
127             }
128             
129             for (String JavaDoc fqn : unfiltered) {
130                 if (!filtered.contains(fqn))
131                     fixes.add(new FixImport(file, fqn, false));
132             }
133         }
134         
135         JavaHintsProvider.LOG.log(Level.FINE, "ImportClassEnabler.create finished."); //NOI18N
136

137         return fixes;
138     }
139     
140     public synchronized void cancel() {
141         JavaHintsProvider.LOG.log(Level.FINE, "ImportClassEnabler.cancel called."); //NOI18N
142

143         cancelled = true;
144         
145         if (compImports != null) {
146             compImports.cancel();
147         }
148     }
149     
150     public String JavaDoc getId() {
151         return ImportClassEnabler.class.getName();
152     }
153     
154     public String JavaDoc getDisplayName() {
155         return "Add Import Fix";
156     }
157     
158     public String JavaDoc getDescription() {
159         return "Add Import Fix";
160     }
161     
162     private synchronized void resume() {
163         JavaHintsProvider.LOG.log(Level.FINE, "ImportClassEnabler.resume called."); //NOI18N
164

165         cancelled = false;
166     }
167     
168     private synchronized boolean isCancelled() {
169         return cancelled;
170     }
171     
172     private boolean cancelled;
173     private ComputeImports compImports;
174     
175     private synchronized void setComputeImports(ComputeImports compImports) {
176         this.compImports = compImports;
177     }
178     
179     public Pair<List JavaDoc<String JavaDoc>, List JavaDoc<String JavaDoc>> getCandidateFQNs(CompilationInfo info, FileObject file, String JavaDoc simpleName, Data<ImportCandidatesHolder> data) {
180         ImportCandidatesHolder holder = data.getData();
181         
182         if (holder == null) {
183             data.setData(holder = new ImportCandidatesHolder());
184         }
185         
186         Pair<Map JavaDoc<String JavaDoc, List JavaDoc<String JavaDoc>>, Map JavaDoc<String JavaDoc, List JavaDoc<String JavaDoc>>> result = holder.getCandidates();
187         
188         if (result == null || result.getA() == null || result.getB() == null) {
189             //compute imports:
190
Map JavaDoc<String JavaDoc, List JavaDoc<String JavaDoc>> candidates = new HashMap JavaDoc<String JavaDoc, List JavaDoc<String JavaDoc>>();
191             ComputeImports imp = new ComputeImports();
192             
193             setComputeImports(imp);
194             
195             ComputeImports.Pair<Map JavaDoc<String JavaDoc, List JavaDoc<TypeElement>>, Map JavaDoc<String JavaDoc, List JavaDoc<TypeElement>>> rawCandidates = imp.computeCandidates(info);
196             
197             setComputeImports(null);
198             
199             if (isCancelled()) {
200                 JavaHintsProvider.LOG.log(Level.FINE, "ImportClassEnabler.getCandidateFQNs cancelled, returning."); //NOI18N
201

202                 return null;
203             }
204             
205             for (String JavaDoc sn : rawCandidates.a.keySet()) {
206                 List JavaDoc<String JavaDoc> c = new ArrayList JavaDoc<String JavaDoc>();
207                 
208                 for (TypeElement te : rawCandidates.a.get(sn)) {
209                     c.add(te.getQualifiedName().toString());
210                 }
211                 
212                 candidates.put(sn, c);
213             }
214             
215             Map JavaDoc<String JavaDoc, List JavaDoc<String JavaDoc>> notFilteredCandidates = new HashMap JavaDoc<String JavaDoc, List JavaDoc<String JavaDoc>>();
216             
217             for (String JavaDoc sn : rawCandidates.b.keySet()) {
218                 List JavaDoc<String JavaDoc> c = new ArrayList JavaDoc<String JavaDoc>();
219                 
220                 for (TypeElement te : rawCandidates.b.get(sn)) {
221                     c.add(te.getQualifiedName().toString());
222                 }
223                 
224                 notFilteredCandidates.put(sn, c);
225             }
226             
227             result = new Pair(candidates, notFilteredCandidates);
228             
229             holder.setCandidates(result);
230         }
231         
232         List JavaDoc<String JavaDoc> candList = result.getA().get(simpleName);
233         List JavaDoc<String JavaDoc> notFilteredCandList = result.getB().get(simpleName);
234         
235         return new Pair(candList, notFilteredCandList);
236     }
237     
238     public static class ImportCandidatesHolder {
239         private Pair<Map JavaDoc<String JavaDoc, List JavaDoc<String JavaDoc>>, Map JavaDoc<String JavaDoc, List JavaDoc<String JavaDoc>>> candidates;
240         
241         public Pair<Map JavaDoc<String JavaDoc, List JavaDoc<String JavaDoc>>, Map JavaDoc<String JavaDoc, List JavaDoc<String JavaDoc>>> getCandidates() {
242             return candidates;
243         }
244         
245         public void setCandidates(Pair<Map JavaDoc<String JavaDoc, List JavaDoc<String JavaDoc>>, Map JavaDoc<String JavaDoc, List JavaDoc<String JavaDoc>>> candidates) {
246             this.candidates = candidates;
247         }
248     }
249     
250     static final class FixImport implements Fix {
251         
252         private FileObject file;
253         private String JavaDoc fqn;
254         private boolean isValid;
255         
256         public FixImport(FileObject file, String JavaDoc fqn, boolean isValid) {
257             this.file = file;
258             this.fqn = fqn;
259             this.isValid = isValid;
260         }
261         
262         public String JavaDoc getText() {
263             if (isValid)
264                 return NbBundle.getMessage(ImportClassEnabler.class, "Add_import_for_X", new Object JavaDoc[] {fqn});
265             else
266                 return "<html><font color='#808080'><s>" + NbBundle.getMessage(ImportClassEnabler.class, "Add_import_for_X", new Object JavaDoc[] {fqn});
267         }
268
269         public ChangeInfo implement() {
270             JavaSource js = JavaSource.forFileObject(file);
271             
272             CancellableTask task = new CancellableTask<WorkingCopy>() {
273                 
274                     public void run(WorkingCopy copy) throws Exception JavaDoc {
275                         if (copy.toPhase(Phase.RESOLVED).compareTo(Phase.RESOLVED) < 0)
276                            return;
277                   
278                         TypeElement te = copy.getElements().getTypeElement(fqn);
279                         
280                         if (te == null) {
281                             Logger.getAnonymousLogger().warning(String.format("Attempt to fix import for FQN: %s, which does not have a TypeElement in currect context", fqn));
282                             return ;
283                         }
284                         
285                         CompilationUnitTree cut = SourceUtils.addImports(
286                             copy.getCompilationUnit(),
287                             Collections.singletonList(te.getQualifiedName().toString()),
288                             copy.getTreeMaker()
289                         );
290                         copy.rewrite(copy.getCompilationUnit(), cut);
291                     }
292                     
293                     public void cancel() {
294                     }
295             };
296             try {
297                 js.runModificationTask(task).commit();
298                 return null;
299             } catch (IOException JavaDoc ex) {
300                 ErrorManager.getDefault().notify(ex);
301             }
302             return null;
303         }
304         
305         @Override JavaDoc
306         public int hashCode() {
307             return fqn.hashCode();
308         }
309         
310         @Override JavaDoc
311         public boolean equals(Object JavaDoc o) {
312             if (o instanceof FixImport) {
313                 return fqn.equals(((FixImport) o).fqn);
314             }
315             
316             return false;
317         }
318     }
319 }
320
Popular Tags