6 package com.google.appinventor.components.scripts;
8 import java.io.IOException;
10 import java.util.HashSet;
11 import java.util.TreeMap;
12 import java.util.TreeSet;
13 import java.util.LinkedHashMap;
17 import javax.tools.Diagnostic;
18 import javax.tools.Diagnostic.Kind;
19 import javax.tools.FileObject;
23 private static final String OUTPUT_FILE_NAME =
"ComponentsTranslation.java";
24 private static final String AUTOGEN_OUTPUT_FILE_NAME =
"AutogeneratedOdeMessages.java";
26 private Map<String, String> tooltips =
new TreeMap<>();
27 private Map<String, Set<String>> tooltipComponent =
new TreeMap<>();
28 private Set<String> collisionKeys =
new HashSet<>();
30 private void outputComponent(
ComponentInfo component, Set<String> outProperties,
31 Set<String> outMethods, Set<String> outEvents, StringBuilder sb) {
32 if (component.getExternal()) {
35 Map<String, Parameter> parameters =
new LinkedHashMap<String, Parameter>();
36 sb.append(
"\n\n/* Component: " + component.getName() +
" */\n\n");
37 sb.append(
" map.put(\"COMPONENT-" + component.getName() +
"\", MESSAGES."
38 + Character.toLowerCase(component.getName().charAt(0)) + component.getName().substring(1)
39 +
"ComponentPallette());\n\n");
40 sb.append(
" map.put(\"" + component.getName() +
"-helpString\", MESSAGES."
41 + component.getName() +
"HelpStringComponentPallette());\n\n");
42 sb.append(
"\n\n/* Properties */\n\n");
43 for (Property prop : component.
properties.values()) {
44 String propertyName = prop.name;
45 if (prop.isUserVisible()
47 || prop.isDeprecated()
50 sb.append(
" map.put(\"PROPERTY-" + propertyName +
"\", MESSAGES." + propertyName +
"Properties());\n");
51 outProperties.add(propertyName);
54 sb.append(
"\n\n/* Events */\n\n");
56 String propertyName =
event.name;
61 sb.append(
" map.put(\"EVENT-" + propertyName +
"\", MESSAGES." + propertyName +
"Events());\n");
62 for (
Parameter parameter : event.parameters) {
63 parameters.put(parameter.
name, parameter);
65 outEvents.add(propertyName);
68 sb.append(
"\n\n/* Methods */\n\n");
70 String propertyName = method.name;
71 if (method.userVisible
75 sb.append(
" map.put(\"METHOD-" + propertyName +
"\", MESSAGES." + propertyName +
"Methods());\n");
76 for (
Parameter parameter : method.parameters) {
77 parameters.put(parameter.
name, parameter);
79 outMethods.add(propertyName);
84 parameters.put(
"notAlreadyHandled",
new Parameter(
"notAlreadyHandled",
"boolean"));
85 sb.append(
"\n\n/* Parameters */\n\n");
86 for (
Parameter parameter : parameters.values()) {
87 sb.append(
" map.put(\"PARAM-" + parameter.name +
"\", MESSAGES." +
88 Character.toLowerCase(parameter.name.charAt(0)) + parameter.name.substring(1) +
93 private void outputCategory(String category, StringBuilder sb) {
95 String[] parts = category.split(
" ");
96 sb.append(
" map.put(\"CATEGORY-" + category +
"\", MESSAGES." + parts[0].replaceAll(
"[^A-Za-z0-9]",
"").toLowerCase());
97 for (
int i = 1; i < parts.length; i++) {
98 String lower = parts[i].replaceAll(
"[^A-Za-z0-9]",
"").toLowerCase();
99 sb.append(Character.toUpperCase(lower.charAt(0)));
100 sb.append(lower.substring(1));
102 sb.append(
"ComponentPallette());\n");
105 private void outputPropertyCategory(String category, StringBuilder sb) {
106 sb.append(
" map.put(\"CATEGORY-");
108 sb.append(
"\", MESSAGES.");
110 sb.append(
"PropertyCategory());\n");
114 Map<String, Property> outProperties, Map<String, Method> outMethods,
115 Map<String, Event> outEvents, StringBuilder sb) {
116 sb.append(
" @DefaultMessage(\"");
117 sb.append(component.getName());
119 sb.append(
" @Description(\"\")\n");
120 sb.append(
" String ");
121 sb.append(Character.toLowerCase(component.getName().charAt(0)));
122 sb.append(component.getName().substring(1));
123 sb.append(
"ComponentPallette();\n\n");
124 sb.append(
" @DefaultMessage(\"");
125 sb.append(sanitize(component.description));
127 sb.append(
" @Description(\"\")\n");
128 sb.append(
" String ");
129 sb.append(component.getName());
130 sb.append(
"HelpStringComponentPallette();\n\n");
131 for (Property property : component.
properties.values()) {
132 if (property.isUserVisible() || component.
designerProperties.containsKey(property.name) ||
133 property.isDeprecated()) {
134 outProperties.put(property.name, property);
138 if (method.userVisible || method.deprecated) {
139 outMethods.put(method.name, method);
143 if (event.userVisible || event.deprecated) {
144 outEvents.put(event.name, event);
149 private void outputPropertyAutogen(Property property, StringBuilder sb) {
150 sb.append(
" @DefaultMessage(\"");
151 sb.append(sanitize(property.name));
153 sb.append(
" @Description(\"\")\n");
154 sb.append(
" String ");
155 sb.append(property.name);
156 sb.append(
"Properties();\n\n");
159 private void outputMethodAutogen(
Method method, Map<String, Parameter> outParameters, StringBuilder sb) {
160 sb.append(
" @DefaultMessage(\"");
161 sb.append(sanitize(method.name));
163 sb.append(
" @Description(\"\")\n");
164 sb.append(
" String ");
165 sb.append(method.name);
166 sb.append(
"Methods();\n\n");
168 outParameters.put(param.
name, param);
172 private void outputEventAutogen(
Event event, Map<String, Parameter> outParameters, StringBuilder sb) {
173 sb.append(
" @DefaultMessage(\"");
174 sb.append(sanitize(event.name));
176 sb.append(
" @Description(\"\")\n");
177 sb.append(
" String ");
178 sb.append(event.name);
179 sb.append(
"Events();\n\n");
181 outParameters.put(param.
name, param);
185 private void outputParameterAutogen(
Parameter parameter, StringBuilder sb) {
186 sb.append(
" @DefaultMessage(\"");
187 sb.append(sanitize(parameter.
name));
189 sb.append(
" @Description(\"\")\n");
190 sb.append(
" String ");
191 sb.append(parameter.
name);
192 sb.append(
"Params();\n\n");
195 private void outputCategoryAutogen(String category, StringBuilder sb) {
196 String[] parts = category.split(
" ");
197 sb.append(
" @DefaultMessage(\"");
200 sb.append(
" @Description(\"\")\n");
201 sb.append(
" String ");
202 sb.append(parts[0].replaceAll(
"[^A-Za-z0-9]",
"").toLowerCase());
203 for (
int i = 1; i < parts.length; i++) {
204 String lower = parts[i].replaceAll(
"[^A-Za-z0-9]",
"").toLowerCase();
205 sb.append(Character.toUpperCase(lower.charAt(0)));
206 sb.append(lower.substring(1));
208 sb.append(
"ComponentPallette();\n\n");
211 private void outputPropertyCategoryAutogen(String category, StringBuilder sb) {
212 sb.append(
" @DefaultMessage(\"");
215 sb.append(
" @Description(\"\")\n");
216 sb.append(
" String ");
218 sb.append(
"PropertyCategory();\n\n");
221 private String sanitize(String input) {
222 return input.replaceAll(
"\r",
"").replaceAll(
"\n",
"").replaceAll(
"\\\\",
"\\\\\\\\")
223 .replaceAll(
"\"",
"\\\\\"").replaceAll(
"'",
"''").replaceAll(
"[ \t]+",
" ").trim();
226 private void storeTooltip(
ComponentInfo component, String name, String suffix,
227 String description) {
228 String key = name + suffix;
229 String value = tooltips.get(key);
230 if (collisionKeys.contains(key)) {
232 key = component.getName() +
"__" + key;
233 tooltips.put(key, description);
234 }
else if (value ==
null) {
236 tooltips.put(key, description);
240 }
else if (!value.equals(description)) {
242 collisionKeys.add(key);
243 for (String componentName : tooltipComponent.get(key)) {
244 tooltips.put(componentName +
"__" + key, value);
246 key = component.getName() +
"__" + key;
247 tooltips.put(key, description);
251 tooltipComponent.get(key).add(component.getName());
256 for (Property property : component.
properties.values()) {
257 storeTooltip(component, property.name,
"PropertyDescriptions", property.getDescription());
260 storeTooltip(component, method.name,
"MethodDescriptions", method.description);
263 storeTooltip(component, event.name,
"EventDescriptions", event.description);
268 Set<String> categories =
new TreeSet<>();
269 Map<String, Property> properties =
new TreeMap<>();
270 Map<String, Method> methods =
new TreeMap<>();
271 Map<String, Event> events =
new TreeMap<>();
272 Map<String, Parameter> parameters =
new TreeMap<>();
273 StringBuilder sb =
new StringBuilder();
274 sb.append(
"// THIS FILE IS AUTOMATICALLY GENERATED DURING COMPILATION.\n");
275 sb.append(
"// DO NOT EDIT THIS FILE. ANY CHANGES WILL BE OVERWRITTEN.\n\n");
276 sb.append(
"package com.google.appinventor.client;\n\n");
277 sb.append(
"import com.google.gwt.i18n.client.Messages;\n\n");
278 sb.append(
"public interface AutogeneratedOdeMessages extends Messages {\n");
279 sb.append(
"\n /* Components */\n");
282 outputComponentAutogen(component, properties, methods, events, sb);
283 computeTooltipMap(component);
286 for (String key : collisionKeys) {
287 tooltips.remove(key);
289 sb.append(
"\n /* Properties */\n");
290 for (Map.Entry<String, Property> entry : properties.entrySet()) {
291 outputPropertyAutogen(entry.getValue(), sb);
293 sb.append(
"\n /* Methods */\n");
294 for (Map.Entry<String,
Method> entry : methods.entrySet()) {
295 outputMethodAutogen(entry.getValue(), parameters, sb);
297 sb.append(
"\n /* Events */\n");
298 for (Map.Entry<String,
Event> entry : events.entrySet()) {
299 outputEventAutogen(entry.getValue(), parameters, sb);
301 for (Map.Entry<String, String> entry : tooltips.entrySet()) {
302 sb.append(
" @DefaultMessage(\"");
303 sb.append(sanitize(entry.getValue()));
305 sb.append(
" @Description(\"\")\n");
306 sb.append(
" String ");
307 sb.append(entry.getKey());
308 sb.append(
"();\n\n");
310 sb.append(
"\n /* Parameters */\n");
311 for (Map.Entry<String,
Parameter> entry : parameters.entrySet()) {
312 outputParameterAutogen(entry.getValue(), sb);
314 sb.append(
"\n /* Component Categories */\n");
315 for (String category : categories) {
316 outputCategoryAutogen(category, sb);
318 sb.append(
"\n /* Property Categories */\n");
319 outputPropertyCategoryAutogen(
"Appearance", sb);
320 outputPropertyCategoryAutogen(
"Behavior", sb);
321 outputPropertyCategoryAutogen(
"Unspecified", sb);
323 FileObject src = createOutputFileObject(AUTOGEN_OUTPUT_FILE_NAME);
324 Writer writer = src.openWriter();
325 writer.write(sb.toString());
328 messager.printMessage(Kind.NOTE,
"Wrote file " + src.toUri());
334 StringBuilder sb =
new StringBuilder();
335 sb.append(
"package com.google.appinventor.client;\n");
337 sb.append(
"import java.util.HashMap;\n");
338 sb.append(
"import java.util.Map;\n");
340 sb.append(
"import static com.google.appinventor.client.Ode.MESSAGES;\n");
342 sb.append(
"public class ComponentsTranslation {\n");
343 sb.append(
" public static Map<String, String> myMap = map();\n\n");
344 sb.append(
" private static String getName(String key) {\n");
345 sb.append(
" String value = myMap.get(key);\n");
346 sb.append(
" if (key == null) {\n");
347 sb.append(
" return \"**Missing key in ComponentsTranslations**\";\n");
348 sb.append(
" } else {\n");
349 sb.append(
" return value;\n");
352 sb.append(
" public static String getPropertyName(String key) {\n");
353 sb.append(
" String value = getName(\"PROPERTY-\" + key);\n");
354 sb.append(
" if(value == null) return key;\n");
355 sb.append(
" return value;\n");
357 sb.append(
" public static String getPropertyDescription(String key) {\n");
358 sb.append(
" String value = getName(\"PROPDESC-\" + key);\n");
359 sb.append(
" if(value == null) return key;\n");
360 sb.append(
" return value;\n");
362 sb.append(
" public static String getMethodName(String key) {\n");
363 sb.append(
" String value = getName(\"METHOD-\" + key);\n");
364 sb.append(
" if(value == null) return key;\n");
365 sb.append(
" return value;\n");
368 sb.append(
" public static String getEventName(String key) {\n");
369 sb.append(
" String value = getName(\"EVENT-\" + key);\n");
370 sb.append(
" if(value == null) return key;\n");
371 sb.append(
" return value;\n");
374 sb.append(
" public static String getComponentName(String key) {\n");
375 sb.append(
" String value = getName(\"COMPONENT-\" + key);\n");
376 sb.append(
" if(value == null) return key;\n");
377 sb.append(
" return value;\n");
380 sb.append(
" public static String getCategoryName(String key) {\n");
381 sb.append(
" String value = getName(\"CATEGORY-\" + key);\n");
382 sb.append(
" if(value == null) return key;\n");
383 sb.append(
" return value;\n");
386 sb.append(
" public static String getComponentHelpString(String key) {\n");
387 sb.append(
" String value = getName(key + \"-helpString\");\n");
388 sb.append(
" if(value == null) return key;\n");
389 sb.append(
" return value;\n");
391 sb.append(
" public static HashMap<String, String> map() {\n");
392 sb.append(
" HashMap<String, String> map = new HashMap<String, String>();\n");
395 Set<String> categories =
new TreeSet<>();
396 Set<String> properties =
new TreeSet<>();
397 Set<String> methods =
new TreeSet<>();
398 Set<String> events =
new TreeSet<>();
401 outputComponent(component, properties, methods, events, sb);
404 sb.append(
"\n\n /* Descriptions */\n\n");
405 for (String key : tooltips.keySet()) {
406 if (key.endsWith(
"PropertyDescriptions")) {
407 sb.append(
" map.put(\"PROPDESC-");
408 sb.append(key.replaceAll(
"__",
"."));
409 sb.append(
"\", MESSAGES.");
412 }
else if (key.endsWith(
"MethodDescriptions")) {
413 sb.append(
" map.put(\"METHODDESC-");
414 sb.append(key.replaceAll(
"__",
"."));
415 sb.append(
"\", MESSAGES.");
418 }
else if (key.endsWith(
"EventDescriptions")) {
419 sb.append(
" map.put(\"EVENTDESC-");
420 sb.append(key.replaceAll(
"__",
"."));
421 sb.append(
"\", MESSAGES.");
426 sb.append(
"\n\n /* Categories */\n\n");
427 for (String category : categories) {
428 outputCategory(category, sb);
430 sb.append(
" return map;\n");
433 FileObject src = createOutputFileObject(OUTPUT_FILE_NAME);
434 Writer writer = src.openWriter();
435 writer.write(sb.toString());
438 messager.printMessage(Diagnostic.Kind.NOTE,
"Wrote file " + src.toUri());