Lines 42-241
Link Here
|
42 |
|
42 |
|
43 |
package org.netbeans.modules.java.source.ui; |
43 |
package org.netbeans.modules.java.source.ui; |
44 |
|
44 |
|
45 |
import java.io.File; |
|
|
46 |
import java.io.IOException; |
45 |
import java.io.IOException; |
47 |
import java.net.URL; |
46 |
import java.util.ArrayList; |
|
|
47 |
import java.util.Collection; |
48 |
import java.util.Collections; |
49 |
import java.util.List; |
48 |
import java.util.Set; |
50 |
import java.util.Set; |
|
|
51 |
import java.util.concurrent.CopyOnWriteArrayList; |
52 |
import java.util.concurrent.atomic.AtomicBoolean; |
53 |
import javax.lang.model.element.Element; |
49 |
import javax.lang.model.element.ElementKind; |
54 |
import javax.lang.model.element.ElementKind; |
50 |
import javax.lang.model.element.Modifier; |
55 |
import javax.lang.model.element.Modifier; |
51 |
import javax.lang.model.element.TypeElement; |
56 |
import javax.lang.model.element.TypeElement; |
52 |
import javax.swing.Icon; |
57 |
import javax.swing.Icon; |
53 |
import org.netbeans.api.annotations.common.CheckForNull; |
|
|
54 |
import org.netbeans.api.annotations.common.NonNull; |
58 |
import org.netbeans.api.annotations.common.NonNull; |
55 |
import org.netbeans.api.annotations.common.NullAllowed; |
59 |
import org.netbeans.api.annotations.common.NullAllowed; |
56 |
import org.netbeans.api.java.classpath.ClassPath; |
|
|
57 |
import org.netbeans.api.java.source.ClasspathInfo; |
60 |
import org.netbeans.api.java.source.ClasspathInfo; |
|
|
61 |
import org.netbeans.api.java.source.CompilationController; |
58 |
import org.netbeans.api.java.source.ElementHandle; |
62 |
import org.netbeans.api.java.source.ElementHandle; |
59 |
import org.netbeans.api.java.source.SourceUtils; |
63 |
import org.netbeans.api.java.source.JavaSource; |
60 |
import org.netbeans.api.java.source.ui.ElementOpen; |
64 |
import org.netbeans.api.java.source.Task; |
61 |
import org.netbeans.api.project.Project; |
65 |
import org.netbeans.api.project.Project; |
62 |
import org.netbeans.api.project.ProjectInformation; |
66 |
import org.netbeans.modules.java.source.indexing.TransactionContext; |
63 |
import org.netbeans.api.project.ProjectUtils; |
67 |
import org.netbeans.modules.java.source.parsing.FileManagerTransaction; |
64 |
import org.netbeans.modules.java.source.parsing.FileObjects; |
68 |
import org.netbeans.modules.java.source.parsing.ProcessorGenerated; |
65 |
import org.netbeans.modules.java.source.usages.ClassIndexImpl; |
69 |
import org.netbeans.modules.java.source.usages.ClassIndexImpl; |
66 |
import org.netbeans.modules.java.ui.Icons; |
70 |
import org.netbeans.modules.java.source.usages.ClasspathInfoAccessor; |
67 |
import org.netbeans.spi.java.classpath.support.ClassPathSupport; |
71 |
import org.netbeans.spi.jumpto.support.AsyncDescriptor; |
|
|
72 |
import org.netbeans.spi.jumpto.support.DescriptorChangeEvent; |
73 |
import org.netbeans.spi.jumpto.support.DescriptorChangeListener; |
68 |
import org.netbeans.spi.jumpto.symbol.SymbolDescriptor; |
74 |
import org.netbeans.spi.jumpto.symbol.SymbolDescriptor; |
69 |
import org.openide.filesystems.FileObject; |
75 |
import org.openide.filesystems.FileObject; |
70 |
import org.openide.filesystems.FileUtil; |
|
|
71 |
import org.openide.util.Exceptions; |
76 |
import org.openide.util.Exceptions; |
|
|
77 |
import org.openide.util.Pair; |
78 |
import org.openide.util.Parameters; |
79 |
import org.openide.util.RequestProcessor; |
72 |
|
80 |
|
73 |
/** |
81 |
/** |
74 |
* |
82 |
* |
75 |
* @author Tomas Zezula |
83 |
* @author Tomas Zezula |
76 |
*/ |
84 |
*/ |
77 |
public class JavaSymbolDescriptor extends SymbolDescriptor { |
85 |
final class AsyncJavaSymbolDescriptor extends JavaSymbolDescriptorBase implements AsyncDescriptor<SymbolDescriptor> { |
78 |
|
86 |
|
79 |
private final String simpleName; |
87 |
private static final RequestProcessor WORKER = new RequestProcessor(AsyncJavaSymbolDescriptor.class); |
80 |
private final String simpleNameSuffix; |
88 |
private static final String INIT = "<init>"; //NOI18N |
81 |
private final ElementHandle<TypeElement> owner; |
|
|
82 |
private final ElementHandle<?> me; |
83 |
private final ElementKind kind; |
84 |
private final Set<Modifier> modifiers; |
85 |
private final FileObject root; |
86 |
private final Project project; |
87 |
private final ClassIndexImpl ci; |
88 |
private FileObject cachedFo; |
89 |
private volatile String cachedPath; |
90 |
|
89 |
|
91 |
public JavaSymbolDescriptor ( |
90 |
private final String ident; |
92 |
@NonNull final String simpleName, |
91 |
private final List<DescriptorChangeListener<SymbolDescriptor>> listeners; |
93 |
@NullAllowed final String simpleNameSuffix, |
92 |
private final AtomicBoolean initialized; |
94 |
@NonNull final ElementKind kind, |
93 |
|
95 |
@NonNull final Set<Modifier> modifiers, |
94 |
AsyncJavaSymbolDescriptor ( |
96 |
@NonNull final ElementHandle<TypeElement> owner, |
|
|
97 |
@NonNull final ElementHandle<?> me, |
98 |
@NullAllowed final Project project, |
95 |
@NullAllowed final Project project, |
99 |
@NonNull final FileObject root, |
96 |
@NonNull final FileObject root, |
100 |
@NonNull final ClassIndexImpl ci) { |
97 |
@NonNull final ClassIndexImpl ci, |
101 |
assert simpleName != null; |
98 |
@NonNull final ElementHandle<TypeElement> owner, |
102 |
assert kind != null; |
99 |
@NonNull final String ident) { |
103 |
assert modifiers != null; |
100 |
super(owner, project, root, ci); |
104 |
assert owner != null; |
101 |
assert ident != null; |
105 |
assert me != null; |
102 |
this.ident = ident; |
106 |
assert root != null; |
103 |
this.listeners = new CopyOnWriteArrayList<>(); |
107 |
assert ci != null; |
104 |
this.initialized = new AtomicBoolean(); |
108 |
this.simpleName = simpleName; |
|
|
109 |
this.simpleNameSuffix = simpleNameSuffix; |
110 |
this.kind = kind; |
111 |
this.modifiers = modifiers; |
112 |
this.owner = owner; |
113 |
this.me = me; |
114 |
this.root = root; |
115 |
this.project = project; |
116 |
this.ci = ci; |
117 |
} |
105 |
} |
118 |
|
106 |
|
119 |
@Override |
107 |
@Override |
120 |
public Icon getIcon() { |
108 |
public Icon getIcon() { |
121 |
return Icons.getElementIcon(kind, modifiers); |
109 |
initialize(); |
|
|
110 |
return null; |
122 |
} |
111 |
} |
123 |
|
112 |
|
124 |
@Override |
113 |
@Override |
125 |
public String getSymbolName() { |
114 |
public String getSymbolName() { |
126 |
return simpleNameSuffix == null ? |
115 |
initialize(); |
127 |
simpleName : |
116 |
return ident; |
128 |
simpleName + simpleNameSuffix; |
|
|
129 |
} |
117 |
} |
130 |
|
118 |
|
131 |
@Override |
119 |
@Override |
132 |
public String getSimpleName() { |
120 |
public String getSimpleName() { |
133 |
return simpleName; |
121 |
return ident; |
134 |
} |
122 |
} |
135 |
|
123 |
|
136 |
@Override |
124 |
@Override |
137 |
public String getOwnerName() { |
125 |
public void open() { |
138 |
return owner.getQualifiedName(); |
126 |
final Collection<? extends SymbolDescriptor> symbols = resolve(); |
|
|
127 |
if (!symbols.isEmpty()) { |
128 |
symbols.iterator().next().open(); |
129 |
} |
139 |
} |
130 |
} |
140 |
|
131 |
|
141 |
|
132 |
private void initialize() { |
142 |
@Override |
133 |
if (initialized.compareAndSet(false, true)) { |
143 |
public FileObject getFileObject() { |
134 |
final Runnable action = new Runnable() { |
144 |
if (cachedFo == null) { |
135 |
@Override |
145 |
final ClasspathInfo cpInfo = ClasspathInfo.create(ClassPath.EMPTY, |
136 |
public void run() { |
146 |
ClassPath.EMPTY, ClassPathSupport.createClassPath(root)); |
137 |
final Collection<? extends SymbolDescriptor> symbols = resolve(); |
147 |
cachedFo = SourceUtils.getFile(owner, cpInfo); |
138 |
fireDescriptorChange(symbols); |
148 |
} |
|
|
149 |
return cachedFo; |
150 |
} |
151 |
|
152 |
@Override |
153 |
@NonNull |
154 |
public String getFileDisplayPath() { |
155 |
String res = cachedPath; |
156 |
if (res == null) { |
157 |
final File rootFile = FileUtil.toFile(root); |
158 |
if (rootFile != null) { |
159 |
try { |
160 |
final String binaryName = owner.getBinaryName(); |
161 |
String relativePath = ci.getSourceName(binaryName); |
162 |
if (relativePath == null) { |
163 |
relativePath = binaryName; |
164 |
int lastDot = relativePath.lastIndexOf('.'); //NOI18N |
165 |
int csIndex = relativePath.indexOf('$', lastDot); //NOI18N |
166 |
if (csIndex > 0 && csIndex < relativePath.length()-1) { |
167 |
relativePath = binaryName.substring(0, csIndex); |
168 |
} |
169 |
relativePath = String.format( |
170 |
"%s.%s", //NOI18N |
171 |
FileObjects.convertPackage2Folder(relativePath, File.separatorChar), |
172 |
FileObjects.JAVA); |
173 |
} |
174 |
res = new File (rootFile, relativePath).getAbsolutePath(); |
175 |
} catch (IOException | InterruptedException e) { |
176 |
Exceptions.printStackTrace(e); |
177 |
} |
139 |
} |
178 |
} |
140 |
}; |
179 |
if (res == null) { |
141 |
WORKER.execute(action); |
180 |
final FileObject fo = getFileObject(); |
|
|
181 |
res = fo == null ? |
182 |
"" : //NOI18N |
183 |
FileUtil.getFileDisplayName(fo); |
184 |
} |
185 |
cachedPath = res; |
186 |
} |
187 |
return res; |
188 |
} |
189 |
|
190 |
|
191 |
|
192 |
@Override |
193 |
public void open() { |
194 |
FileObject file = getFileObject(); |
195 |
if (file != null) { |
196 |
ClasspathInfo cpInfo = ClasspathInfo.create(file); |
197 |
|
198 |
ElementOpen.open(cpInfo, me); |
199 |
} |
142 |
} |
200 |
} |
143 |
} |
201 |
|
144 |
|
202 |
@Override |
145 |
@Override |
203 |
public String getProjectName() { |
146 |
public void addDescriptorChangeListener(@NonNull final DescriptorChangeListener<SymbolDescriptor> listener) { |
204 |
final ProjectInformation info = getProjectInfo(); |
147 |
Parameters.notNull("listener", listener); |
205 |
return info == null ? |
148 |
listeners.add(listener); |
206 |
"" : //NOI18N |
|
|
207 |
info.getDisplayName(); |
208 |
} |
149 |
} |
209 |
|
150 |
|
210 |
@Override |
151 |
@Override |
211 |
public Icon getProjectIcon() { |
152 |
public void removeDescriptorChangeListener(@NonNull final DescriptorChangeListener<SymbolDescriptor> listener) { |
212 |
final ProjectInformation info = getProjectInfo(); |
153 |
Parameters.notNull("listener", listener); |
213 |
return info == null ? |
154 |
listeners.remove(listener); |
214 |
null : |
|
|
215 |
info.getIcon(); |
216 |
} |
155 |
} |
217 |
|
156 |
|
218 |
@Override |
157 |
private void fireDescriptorChange(Collection<? extends SymbolDescriptor> replacement) { |
219 |
public int getOffset() { |
158 |
final DescriptorChangeEvent<SymbolDescriptor> event = new DescriptorChangeEvent<>( |
220 |
//todo: fixme |
159 |
this, |
221 |
return -1; |
160 |
replacement); |
|
|
161 |
for (DescriptorChangeListener<SymbolDescriptor> l : listeners) { |
162 |
l.descriptorChanged(event); |
163 |
} |
222 |
} |
164 |
} |
223 |
|
165 |
|
224 |
@NonNull |
166 |
@NonNull |
225 |
public ElementKind getElementKind() { |
167 |
private Collection<? extends SymbolDescriptor> resolve() { |
226 |
return kind; |
168 |
try { |
|
|
169 |
final List<SymbolDescriptor> symbols = new ArrayList<>(); |
170 |
TransactionContext. |
171 |
beginTrans(). |
172 |
register(FileManagerTransaction.class, FileManagerTransaction.read()). |
173 |
register(ProcessorGenerated.class, ProcessorGenerated.nullWrite()); |
174 |
try { |
175 |
final ClasspathInfo cpInfo = ClasspathInfoAccessor.getINSTANCE().create(getRoot(),null,true,true,false,false); |
176 |
final JavaSource js = JavaSource.create(cpInfo); |
177 |
js.runUserActionTask(new Task<CompilationController>() { |
178 |
@Override |
179 |
public void run (final CompilationController controller) { |
180 |
final TypeElement te = getOwner().resolve(controller); |
181 |
if (te != null) { |
182 |
if (ident.equals(getSimpleName(te, null)) /*TODO && matchesRestrictions(te, restriction)*/) { |
183 |
final String simpleName = te.getSimpleName().toString(); |
184 |
final String simpleNameSuffix = null; |
185 |
final ElementKind kind = te.getKind(); |
186 |
final Set<Modifier> modifiers = te.getModifiers(); |
187 |
final ElementHandle<?> me = ElementHandle.create(te); |
188 |
symbols.add(new ResolvedJavaSymbolDescriptor( |
189 |
AsyncJavaSymbolDescriptor.this, |
190 |
simpleName, |
191 |
simpleNameSuffix, |
192 |
kind, |
193 |
modifiers, |
194 |
me)); |
195 |
} |
196 |
for (Element ne : te.getEnclosedElements()) { |
197 |
if (ident.equals(getSimpleName(ne, te)) /*TODO && matchesRestrictions(ne, restriction)*/) { |
198 |
final Pair<String,String> name = JavaSymbolProvider.getDisplayName(ne, te); |
199 |
final String simpleName = name.first(); |
200 |
final String simpleNameSuffix = name.second(); |
201 |
final ElementKind kind = ne.getKind(); |
202 |
final Set<Modifier> modifiers = ne.getModifiers(); |
203 |
final ElementHandle<?> me = ElementHandle.create(ne); |
204 |
symbols.add(new ResolvedJavaSymbolDescriptor( |
205 |
AsyncJavaSymbolDescriptor.this, |
206 |
simpleName, |
207 |
simpleNameSuffix, |
208 |
kind, |
209 |
modifiers, |
210 |
me)); |
211 |
} |
212 |
} |
213 |
} |
214 |
} |
215 |
}, true); |
216 |
}finally { |
217 |
TransactionContext.get().commit(); |
218 |
} |
219 |
return symbols; |
220 |
} catch (IOException e) { |
221 |
Exceptions.printStackTrace(e); |
222 |
return Collections.<SymbolDescriptor>emptyList(); |
223 |
} |
227 |
} |
224 |
} |
228 |
|
225 |
|
229 |
@NonNull |
226 |
@NonNull |
230 |
public Set<? extends Modifier> getModifiers() { |
227 |
private static String getSimpleName ( |
231 |
return modifiers; |
228 |
@NonNull final Element element, |
|
|
229 |
@NullAllowed final Element enclosingElement) { |
230 |
String result = element.getSimpleName().toString(); |
231 |
if (enclosingElement != null && INIT.equals(result)) { |
232 |
result = enclosingElement.getSimpleName().toString(); |
233 |
} |
234 |
//TODO if (!caseSensitive) { |
235 |
result = result.toLowerCase(); |
236 |
// } |
237 |
return result; |
232 |
} |
238 |
} |
233 |
|
|
|
234 |
@CheckForNull |
235 |
private ProjectInformation getProjectInfo() { |
236 |
return project == null ? |
237 |
null : |
238 |
project.getLookup().lookup(ProjectInformation.class); //Intentionally does not use ProjectUtils.getInformation() it does project icon annotation which is expensive |
239 |
} |
240 |
|
241 |
} |
239 |
} |