Lines 39-51
Link Here
|
39 |
|
39 |
|
40 |
package org.netbeans.modules.editor.lib2; |
40 |
package org.netbeans.modules.editor.lib2; |
41 |
|
41 |
|
42 |
import java.io.IOException; |
42 |
import java.util.List; |
43 |
import java.util.MissingResourceException; |
43 |
import org.netbeans.modules.editor.lib2.actions.EditorActionUtilities; |
44 |
import java.util.PropertyResourceBundle; |
44 |
import org.netbeans.modules.editor.lib2.actions.PresenterEditorAction; |
45 |
import java.util.ResourceBundle; |
|
|
46 |
import java.util.Set; |
45 |
import java.util.Set; |
47 |
import javax.annotation.processing.Filer; |
|
|
48 |
import javax.annotation.processing.ProcessingEnvironment; |
49 |
import javax.annotation.processing.Processor; |
46 |
import javax.annotation.processing.Processor; |
50 |
import javax.annotation.processing.RoundEnvironment; |
47 |
import javax.annotation.processing.RoundEnvironment; |
51 |
import javax.annotation.processing.SupportedAnnotationTypes; |
48 |
import javax.annotation.processing.SupportedAnnotationTypes; |
Lines 55-64
Link Here
|
55 |
import javax.lang.model.element.ExecutableElement; |
52 |
import javax.lang.model.element.ExecutableElement; |
56 |
import javax.lang.model.element.Modifier; |
53 |
import javax.lang.model.element.Modifier; |
57 |
import javax.lang.model.element.TypeElement; |
54 |
import javax.lang.model.element.TypeElement; |
|
|
55 |
import javax.lang.model.element.VariableElement; |
58 |
import javax.lang.model.type.TypeMirror; |
56 |
import javax.lang.model.type.TypeMirror; |
59 |
import javax.lang.model.util.ElementFilter; |
57 |
import javax.lang.model.util.ElementFilter; |
60 |
import javax.swing.Action; |
58 |
import javax.swing.Action; |
61 |
import javax.tools.StandardLocation; |
|
|
62 |
import org.netbeans.api.editor.EditorActionRegistration; |
59 |
import org.netbeans.api.editor.EditorActionRegistration; |
63 |
import org.netbeans.api.editor.EditorActionRegistrations; |
60 |
import org.netbeans.api.editor.EditorActionRegistrations; |
64 |
import org.openide.filesystems.annotations.LayerBuilder; |
61 |
import org.openide.filesystems.annotations.LayerBuilder; |
Lines 67-73
Link Here
|
67 |
import org.openide.util.lookup.ServiceProvider; |
64 |
import org.openide.util.lookup.ServiceProvider; |
68 |
|
65 |
|
69 |
/** |
66 |
/** |
70 |
* Annotation processor for |
67 |
* Annotation processor for {@link EditorActionRegistration} |
|
|
68 |
* and {@link EditorActionRegistrations}. |
71 |
*/ |
69 |
*/ |
72 |
@ServiceProvider(service=Processor.class) |
70 |
@ServiceProvider(service=Processor.class) |
73 |
@SupportedSourceVersion(SourceVersion.RELEASE_6) |
71 |
@SupportedSourceVersion(SourceVersion.RELEASE_6) |
Lines 101-107
Link Here
|
101 |
String methodName; |
99 |
String methodName; |
102 |
TypeMirror swingActionType = processingEnv.getTypeUtils().getDeclaredType( |
100 |
TypeMirror swingActionType = processingEnv.getTypeUtils().getDeclaredType( |
103 |
processingEnv.getElementUtils().getTypeElement("javax.swing.Action")); |
101 |
processingEnv.getElementUtils().getTypeElement("javax.swing.Action")); |
104 |
|
102 |
TypeMirror utilMapType = processingEnv.getTypeUtils().getDeclaredType( |
|
|
103 |
processingEnv.getElementUtils().getTypeElement("java.util.Map")); |
104 |
boolean directActionCreation = false; // Whether construct AlwaysEnabledAction or annotated action directly |
105 |
switch (e.getKind()) { |
105 |
switch (e.getKind()) { |
106 |
case CLASS: |
106 |
case CLASS: |
107 |
className = processingEnv.getElementUtils().getBinaryName((TypeElement)e).toString(); |
107 |
className = processingEnv.getElementUtils().getBinaryName((TypeElement)e).toString(); |
Lines 111-134
Link Here
|
111 |
if (!e.getModifiers().contains(Modifier.PUBLIC)) { |
111 |
if (!e.getModifiers().contains(Modifier.PUBLIC)) { |
112 |
throw new LayerGenerationException(className + " is not public", e); |
112 |
throw new LayerGenerationException(className + " is not public", e); |
113 |
} |
113 |
} |
114 |
boolean hasDefaultCtor = false; |
114 |
ExecutableElement defaultCtor = null; |
|
|
115 |
ExecutableElement mapCtor = null; |
115 |
for (ExecutableElement constructor : ElementFilter.constructorsIn(e.getEnclosedElements())) { |
116 |
for (ExecutableElement constructor : ElementFilter.constructorsIn(e.getEnclosedElements())) { |
116 |
if (constructor.getParameters().isEmpty()) { |
117 |
List<? extends VariableElement> params = constructor.getParameters(); |
117 |
if (!constructor.getModifiers().contains(Modifier.PUBLIC)) { |
118 |
if (params.isEmpty()) { |
118 |
throw new LayerGenerationException("Default constructor of " + className + " is not public", e); |
119 |
defaultCtor = constructor; |
119 |
} |
120 |
|
120 |
hasDefaultCtor = true; |
121 |
} else if (params.size() == 1 && |
121 |
break; |
122 |
processingEnv.getTypeUtils().isAssignable(params.get(0).asType(), utilMapType)) |
|
|
123 |
{ |
124 |
mapCtor = constructor; |
122 |
} |
125 |
} |
123 |
} |
126 |
} |
124 |
if (!hasDefaultCtor) { |
127 |
String msgBase = "No-argument (or single-argument \"Map<String,?> attrs\") constructor"; |
125 |
throw new LayerGenerationException(className + " must have a no-argument constructor", e); |
128 |
if (defaultCtor == null && mapCtor == null) { |
|
|
129 |
throw new LayerGenerationException(msgBase + " not present in " + className, e); |
130 |
} |
131 |
boolean defaultCtorPublic = (defaultCtor != null && defaultCtor.getModifiers().contains(Modifier.PUBLIC)); |
132 |
boolean mapCtorPublic = (mapCtor != null && mapCtor.getModifiers().contains(Modifier.PUBLIC)); |
133 |
if (!defaultCtorPublic && !mapCtorPublic) { |
134 |
throw new LayerGenerationException(msgBase + " not public in " + className, e); |
126 |
} |
135 |
} |
127 |
|
136 |
|
128 |
if (!processingEnv.getTypeUtils().isAssignable(e.asType(), swingActionType)) { |
137 |
if (!processingEnv.getTypeUtils().isAssignable(e.asType(), swingActionType)) { |
129 |
throw new LayerGenerationException(className + " is not assignable to javax.swing.Action", e); |
138 |
throw new LayerGenerationException(className + " is not assignable to javax.swing.Action", e); |
130 |
} |
139 |
} |
131 |
|
140 |
if (mapCtorPublic) { |
|
|
141 |
directActionCreation = true; |
142 |
} |
132 |
methodName = null; |
143 |
methodName = null; |
133 |
break; |
144 |
break; |
134 |
|
145 |
|
Lines 136-153
Link Here
|
136 |
className = processingEnv.getElementUtils().getBinaryName((TypeElement) e.getEnclosingElement()).toString(); |
147 |
className = processingEnv.getElementUtils().getBinaryName((TypeElement) e.getEnclosingElement()).toString(); |
137 |
methodName = e.getSimpleName().toString(); |
148 |
methodName = e.getSimpleName().toString(); |
138 |
if (!e.getModifiers().contains(Modifier.STATIC)) { |
149 |
if (!e.getModifiers().contains(Modifier.STATIC)) { |
139 |
throw new LayerGenerationException(className + "." + methodName + " must be static", e); |
150 |
throw new LayerGenerationException(className + "." + methodName + " must be static", e); // NOI18N |
140 |
} |
151 |
} |
141 |
// It appears that actually even non-public method registration works - so commented following |
152 |
// It appears that actually even non-public method registration works - so commented following |
142 |
// if (!e.getModifiers().contains(Modifier.PUBLIC)) { |
153 |
// if (!e.getModifiers().contains(Modifier.PUBLIC)) { |
143 |
// throw new LayerGenerationException(className + "." + methodName + " must be public", e); |
154 |
// throw new LayerGenerationException(className + "." + methodName + " must be public", e); |
144 |
// } |
155 |
// } |
145 |
if (!((ExecutableElement) e).getParameters().isEmpty()) { |
156 |
List<? extends VariableElement> params = ((ExecutableElement)e).getParameters(); |
146 |
throw new LayerGenerationException(className + "." + methodName + " must not take arguments", e); |
157 |
boolean emptyParams = params.isEmpty(); |
|
|
158 |
boolean mapParam = (params.size() == 1 && processingEnv.getTypeUtils().isAssignable( |
159 |
params.get(0).asType(), utilMapType)); |
160 |
if (!emptyParams && !mapParam) |
161 |
{ |
162 |
throw new LayerGenerationException(className + "." + methodName + |
163 |
" must not take arguments (or have a single-argument \"Map<String,?> attrs\")", e); // NOI18N |
147 |
} |
164 |
} |
148 |
if (swingActionType != null && !processingEnv.getTypeUtils().isAssignable(((ExecutableElement)e).getReturnType(), swingActionType)) { |
165 |
TypeMirror returnType = ((ExecutableElement)e).getReturnType(); |
|
|
166 |
if (swingActionType != null && !processingEnv.getTypeUtils().isAssignable(returnType, swingActionType)) { |
149 |
throw new LayerGenerationException(className + "." + methodName + " is not assignable to javax.swing.Action", e); |
167 |
throw new LayerGenerationException(className + "." + methodName + " is not assignable to javax.swing.Action", e); |
150 |
} |
168 |
} |
|
|
169 |
if (mapParam) { |
170 |
directActionCreation = true; |
171 |
} |
151 |
break; |
172 |
break; |
152 |
|
173 |
|
153 |
default: |
174 |
default: |
Lines 162-170
Link Here
|
162 |
filePath.append("/").append(annotation.mimeType()); |
183 |
filePath.append("/").append(annotation.mimeType()); |
163 |
} |
184 |
} |
164 |
filePath.append("/Actions/").append(actionName).append(".instance"); |
185 |
filePath.append("/Actions/").append(actionName).append(".instance"); |
165 |
LayerBuilder.File file = layer(e).file(filePath.toString()); |
186 |
LayerBuilder layer = layer(e); |
166 |
|
187 |
LayerBuilder.File file = layer.file(filePath.toString()); |
167 |
file.stringvalue("displayName", actionName); |
|
|
168 |
|
188 |
|
169 |
// Resolve icon resource |
189 |
// Resolve icon resource |
170 |
String iconResource = annotation.iconResource(); |
190 |
String iconResource = annotation.iconResource(); |
Lines 199-211
Link Here
|
199 |
file.bundlevalue("popupText", popupText); |
219 |
file.bundlevalue("popupText", popupText); |
200 |
} |
220 |
} |
201 |
|
221 |
|
202 |
file.methodvalue("instanceCreate", "org.openide.awt.Actions", "alwaysEnabled"); |
222 |
// Check presenters |
203 |
if (methodName != null) { |
223 |
String presenterActionName = null; |
204 |
file.methodvalue("delegate", className, methodName); |
224 |
String presenterType = annotation.presenterType(); |
205 |
} else { |
225 |
if (presenterType.length() > 0) { // Non-default presenter type |
206 |
file.newvalue("delegate", className); |
226 |
directActionCreation = true; |
|
|
227 |
} |
228 |
|
229 |
// Check menu path |
230 |
String menuPath = annotation.menuPath(); |
231 |
int menuPosition = annotation.menuPosition(); |
232 |
if (menuPosition != Integer.MAX_VALUE) { |
233 |
StringBuilder presenterFilePath = new StringBuilder(50); |
234 |
presenterFilePath.append("Menu/"); |
235 |
if (menuPath.length() > 0) { |
236 |
presenterFilePath.append(menuPath).append('/'); |
237 |
} |
238 |
presenterFilePath.append(actionName).append(".shadow"); |
239 |
LayerBuilder.File presenterShadowFile = layer.file(presenterFilePath.toString()); |
240 |
if (presenterActionName == null) { |
241 |
presenterActionName = generatePresenterAction(layer, actionName, presenterType); |
242 |
} |
243 |
presenterShadowFile.stringvalue("originalFile", presenterActionName); |
244 |
presenterShadowFile.intvalue("position", menuPosition); |
245 |
presenterShadowFile.write(); |
246 |
} |
247 |
|
248 |
// Check popup path |
249 |
String popupPath = annotation.popupPath(); |
250 |
int popupPosition = annotation.popupPosition(); |
251 |
if (popupPosition != Integer.MAX_VALUE) { |
252 |
StringBuilder presenterFilePath = new StringBuilder(50); |
253 |
presenterFilePath.append("Editors"); |
254 |
if (annotation.mimeType().length() > 0) { |
255 |
filePath.append("/").append(annotation.mimeType()); |
256 |
} |
257 |
if (popupPath.length() > 0) { |
258 |
presenterFilePath.append(popupPath).append('/'); |
259 |
} |
260 |
presenterFilePath.append(actionName).append(".shadow"); |
261 |
LayerBuilder.File presenterShadowFile = layer.file(presenterFilePath.toString()); |
262 |
if (presenterActionName == null) { |
263 |
presenterActionName = generatePresenterAction(layer, actionName, presenterType); |
264 |
} |
265 |
presenterShadowFile.stringvalue("originalFile", presenterActionName); |
266 |
presenterShadowFile.intvalue("position", popupPosition); |
267 |
presenterShadowFile.write(); |
268 |
} |
269 |
|
270 |
int toolBarPosition = annotation.toolBarPosition(); |
271 |
if (toolBarPosition != Integer.MAX_VALUE) { |
272 |
StringBuilder presenterFilePath = new StringBuilder(50); |
273 |
presenterFilePath.append("/Editors/Toolbar/"); |
274 |
if (popupPath.length() > 0) { |
275 |
presenterFilePath.append(popupPath).append('/'); |
276 |
} |
277 |
presenterFilePath.append(actionName).append(".shadow"); |
278 |
LayerBuilder.File presenterShadowFile = layer.file(presenterFilePath.toString()); |
279 |
if (presenterActionName == null) { |
280 |
presenterActionName = generatePresenterAction(layer, actionName, presenterType); |
281 |
} |
282 |
presenterShadowFile.stringvalue("originalFile", presenterActionName); |
283 |
presenterShadowFile.intvalue("position", toolBarPosition); |
284 |
presenterShadowFile.write(); |
285 |
} |
286 |
|
287 |
// Deafult helpID is action's name |
288 |
file.stringvalue("helpID", actionName); |
289 |
|
290 |
// Resolve accelerator through method |
291 |
file.methodvalue(Action.ACCELERATOR_KEY, EditorActionUtilities.class.getName(), "getAccelerator"); |
292 |
|
293 |
// Always generate Action.NAME since although AlwaysEnabledAction tweaks its retrieval to "displayName" |
294 |
// some tools may query FO's properties and expect it there. |
295 |
file.stringvalue(Action.NAME, actionName); |
296 |
|
297 |
if (directActionCreation) { |
298 |
if (methodName != null) { |
299 |
file.methodvalue("instanceCreate", className, methodName); |
300 |
} else { |
301 |
file.newvalue("instanceCreate", className); |
302 |
} |
303 |
|
304 |
} else { // Create always enabled action |
305 |
file.methodvalue("instanceCreate", "org.openide.awt.Actions", "alwaysEnabled"); |
306 |
file.stringvalue("displayName", actionName); |
307 |
|
308 |
if (methodName != null) { |
309 |
file.methodvalue("delegate", className, methodName); |
310 |
} else { |
311 |
file.newvalue("delegate", className); |
312 |
} |
207 |
} |
313 |
} |
208 |
file.write(); |
314 |
file.write(); |
209 |
} |
315 |
} |
210 |
|
316 |
|
|
|
317 |
private String generatePresenterAction(LayerBuilder layer, String actionName, String presenterType) { |
318 |
String presenterActionName = "Editors/ActionPresenters/" + actionName + ".instance"; |
319 |
LayerBuilder.File presenterActionFile = layer.file(presenterActionName); |
320 |
presenterActionFile.methodvalue("instanceCreate", PresenterEditorAction.class.getName(), "create"); |
321 |
presenterActionFile.stringvalue(Action.NAME, actionName); |
322 |
presenterActionFile.stringvalue("PresenterType", presenterType); |
323 |
presenterActionFile.write(); |
324 |
return presenterActionName; |
325 |
} |
326 |
|
211 |
} |
327 |
} |