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 157-170
Link Here
|
157 |
|
178 |
|
158 |
String actionName = annotation.name(); |
179 |
String actionName = annotation.name(); |
159 |
StringBuilder filePath = new StringBuilder(50); |
180 |
StringBuilder filePath = new StringBuilder(50); |
|
|
181 |
String mimeType = annotation.mimeType(); |
160 |
filePath.append("Editors"); |
182 |
filePath.append("Editors"); |
161 |
if (annotation.mimeType().length() > 0) { |
183 |
if (mimeType.length() > 0) { |
162 |
filePath.append("/").append(annotation.mimeType()); |
184 |
filePath.append("/").append(mimeType); |
163 |
} |
185 |
} |
164 |
filePath.append("/Actions/").append(actionName).append(".instance"); |
186 |
filePath.append("/Actions/").append(actionName).append(".instance"); |
165 |
LayerBuilder.File file = layer(e).file(filePath.toString()); |
187 |
LayerBuilder layer = layer(e); |
166 |
|
188 |
LayerBuilder.File file = layer.file(filePath.toString()); |
167 |
file.stringvalue("displayName", actionName); |
189 |
String preferencesKey = annotation.preferencesKey(); |
|
|
190 |
boolean checkBoxPresenter = (preferencesKey.length() > 0); |
168 |
|
191 |
|
169 |
// Resolve icon resource |
192 |
// Resolve icon resource |
170 |
String iconResource = annotation.iconResource(); |
193 |
String iconResource = annotation.iconResource(); |
Lines 199-211
Link Here
|
199 |
file.bundlevalue("popupText", popupText); |
222 |
file.bundlevalue("popupText", popupText); |
200 |
} |
223 |
} |
201 |
|
224 |
|
202 |
file.methodvalue("instanceCreate", "org.openide.awt.Actions", "alwaysEnabled"); |
225 |
// Check presenters |
203 |
if (methodName != null) { |
226 |
String presenterActionName = null; |
204 |
file.methodvalue("delegate", className, methodName); |
227 |
|
205 |
} else { |
228 |
// Check menu path |
206 |
file.newvalue("delegate", className); |
229 |
String menuPath = annotation.menuPath(); |
|
|
230 |
int menuPosition = annotation.menuPosition(); |
231 |
if (menuPosition != Integer.MAX_VALUE) { |
232 |
StringBuilder presenterFilePath = new StringBuilder(50); |
233 |
presenterFilePath.append("Menu/"); |
234 |
if (menuPath.length() > 0) { |
235 |
presenterFilePath.append(menuPath).append('/'); |
236 |
} |
237 |
presenterFilePath.append(actionName).append(".shadow"); |
238 |
LayerBuilder.File presenterShadowFile = layer.file(presenterFilePath.toString()); |
239 |
if (presenterActionName == null) { |
240 |
if (checkBoxPresenter) { // Point directly to AlwaysEnabledAction |
241 |
presenterActionName = "Editors/Actions/" + actionName + ".instance"; |
242 |
} else { |
243 |
presenterActionName = generatePresenterAction(layer, actionName); |
244 |
} |
245 |
} |
246 |
presenterShadowFile.stringvalue("originalFile", presenterActionName); |
247 |
presenterShadowFile.intvalue("position", menuPosition); |
248 |
presenterShadowFile.write(); |
249 |
} |
250 |
|
251 |
// Check popup path |
252 |
String popupPath = annotation.popupPath(); |
253 |
int popupPosition = annotation.popupPosition(); |
254 |
if (popupPosition != Integer.MAX_VALUE) { |
255 |
StringBuilder presenterFilePath = new StringBuilder(50); |
256 |
presenterFilePath.append("Editors/Popup/"); |
257 |
if (mimeType.length() > 0) { |
258 |
presenterFilePath.append(mimeType).append("/"); |
259 |
} |
260 |
if (popupPath.length() > 0) { |
261 |
presenterFilePath.append(popupPath).append('/'); |
262 |
} |
263 |
presenterFilePath.append(actionName).append(".shadow"); |
264 |
LayerBuilder.File presenterShadowFile = layer.file(presenterFilePath.toString()); |
265 |
if (presenterActionName == null) { |
266 |
if (checkBoxPresenter) { // Point directly to AlwaysEnabledAction |
267 |
presenterActionName = "Editors/Actions/" + actionName + ".instance"; |
268 |
} else { |
269 |
presenterActionName = generatePresenterAction(layer, actionName); |
270 |
} |
271 |
} |
272 |
presenterShadowFile.stringvalue("originalFile", presenterActionName); |
273 |
presenterShadowFile.intvalue("position", popupPosition); |
274 |
presenterShadowFile.write(); |
275 |
} |
276 |
|
277 |
int toolBarPosition = annotation.toolBarPosition(); |
278 |
if (toolBarPosition != Integer.MAX_VALUE) { |
279 |
StringBuilder presenterFilePath = new StringBuilder(50); |
280 |
presenterFilePath.append("Editors/Toolbar/"); |
281 |
if (mimeType.length() > 0) { |
282 |
presenterFilePath.append(mimeType).append("/"); |
283 |
} |
284 |
presenterFilePath.append(actionName).append(".shadow"); |
285 |
LayerBuilder.File presenterShadowFile = layer.file(presenterFilePath.toString()); |
286 |
if (presenterActionName == null) { |
287 |
presenterActionName = generatePresenterAction(layer, actionName); |
288 |
} |
289 |
presenterShadowFile.stringvalue("originalFile", presenterActionName); |
290 |
presenterShadowFile.intvalue("position", toolBarPosition); |
291 |
presenterShadowFile.write(); |
292 |
} |
293 |
|
294 |
if (preferencesKey.length() > 0) { |
295 |
file.stringvalue("PreferencesKey", preferencesKey); |
296 |
file.methodvalue("PreferencesNode", EditorActionUtilities.class.getName(), "getGlobalPreferences"); |
297 |
} |
298 |
|
299 |
// Deafult helpID is action's name |
300 |
file.stringvalue("helpID", actionName); |
301 |
|
302 |
// Resolve accelerator through method |
303 |
file.methodvalue(Action.ACCELERATOR_KEY, EditorActionUtilities.class.getName(), "getAccelerator"); |
304 |
|
305 |
// Always generate Action.NAME since although AlwaysEnabledAction tweaks its retrieval to "displayName" |
306 |
// some tools may query FO's properties and expect it there. |
307 |
file.stringvalue(Action.NAME, actionName); |
308 |
|
309 |
if (directActionCreation) { |
310 |
if (methodName != null) { |
311 |
file.methodvalue("instanceCreate", className, methodName); |
312 |
} else { |
313 |
file.newvalue("instanceCreate", className); |
314 |
} |
315 |
|
316 |
} else { // Create always enabled action |
317 |
file.methodvalue("instanceCreate", "org.openide.awt.Actions", "alwaysEnabled"); |
318 |
file.stringvalue("displayName", actionName); |
319 |
|
320 |
if (methodName != null) { |
321 |
file.methodvalue("delegate", className, methodName); |
322 |
} else { |
323 |
file.newvalue("delegate", className); |
324 |
} |
207 |
} |
325 |
} |
208 |
file.write(); |
326 |
file.write(); |
209 |
} |
327 |
} |
210 |
|
328 |
|
|
|
329 |
private String generatePresenterAction(LayerBuilder layer, String actionName) { |
330 |
String presenterActionName = "Editors/ActionPresenters/" + actionName + ".instance"; |
331 |
LayerBuilder.File presenterActionFile = layer.file(presenterActionName); |
332 |
presenterActionFile.methodvalue("instanceCreate", PresenterEditorAction.class.getName(), "create"); |
333 |
presenterActionFile.stringvalue(Action.NAME, actionName); |
334 |
presenterActionFile.write(); |
335 |
return presenterActionName; |
336 |
} |
337 |
|
211 |
} |
338 |
} |