Skip to content

Commit 410111e

Browse files
authored
Merge pull request #2580 from katysaintin/master
Add a Util class to generate rst widgets document
2 parents a9ed226 + 828aec6 commit 410111e

File tree

1 file changed

+363
-0
lines changed

1 file changed

+363
-0
lines changed
Lines changed: 363 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,363 @@
1+
/*******************************************************************************
2+
* Copyright (c) 2023 by CEA .
3+
*
4+
* The full license specifying the redistribution, modification, usage and other rights
5+
* and obligations is included with the distribution of this project in the file "license.txt"
6+
* THIS SOFTWARE IS PROVIDED AS-IS WITHOUT WARRANTY OF ANY KIND, NOT EVEN
7+
*
8+
* THE IMPLIED WARRANTY OF MERCHANTABILITY. THE AUTHOR OF THIS SOFTWARE
9+
* ASSUMES NO RESPONSIBILITY FOR ANY CONSEQUENCE RESULTING FROM THE USE,
10+
* MODIFICATION,OR REDISTRIBUTION OF THIS SOFTWARE.
11+
******************************************************************************/
12+
package org.csstudio.display.builder.model.util;
13+
14+
import java.io.BufferedWriter;
15+
import java.io.File;
16+
import java.io.FileWriter;
17+
import java.lang.reflect.Constructor;
18+
import java.lang.reflect.Field;
19+
import java.lang.reflect.Modifier;
20+
import java.net.URL;
21+
import java.util.Collection;
22+
import java.util.HashMap;
23+
import java.util.HashSet;
24+
import java.util.Map;
25+
import java.util.Map.Entry;
26+
import java.util.Set;
27+
28+
import javax.swing.JFileChooser;
29+
import javax.swing.JFrame;
30+
31+
import org.csstudio.display.builder.model.Widget;
32+
import org.csstudio.display.builder.model.WidgetDescriptor;
33+
import org.csstudio.display.builder.model.WidgetFactory;
34+
import org.csstudio.display.builder.model.WidgetProperty;
35+
import org.csstudio.display.builder.model.WidgetPropertyCategory;
36+
//import org.reflections.ReflectionUtils;
37+
//import org.reflections.Reflections;
38+
//import org.reflections.Store;
39+
40+
/**
41+
* This class generate the property list of all the existing widget in Phoebus
42+
*
43+
* @author ksaintin
44+
*
45+
*/
46+
public class WidgetsInformationUtil {
47+
private static final String WIDGET_DESCRIPTOR = "WIDGET_DESCRIPTOR";
48+
49+
public static enum PropInformation {
50+
name, description, type, category, value, defaultvalue, icon_url, widget_type, version, java_class
51+
};
52+
53+
// Map <widget class, properties map and value>
54+
private static final Map<String, Map<String, Map<String, Object>>> WIDGET_MAP = new HashMap<>();
55+
56+
private static Set<Class<? extends Widget>> getWidgetImplementations(String packageName) {
57+
58+
Set<Class<? extends Widget>> widgetSet = new HashSet<>();
59+
if (packageName == null) {
60+
Set<WidgetDescriptor> widgetDescriptions = WidgetFactory.getInstance().getWidgetDescriptions();
61+
Widget widget = null;
62+
for (WidgetDescriptor desc : widgetDescriptions) {
63+
widget = desc.createWidget();
64+
widgetSet.add(widget.getClass());
65+
}
66+
}
67+
else {
68+
//Use Reflection API uncomment line in xml pom
69+
// Use Kay method to get the list of widget
70+
// TODO take in charge custom package
71+
// Reflections reflections = new Reflections(packageName);
72+
// Set<Class<? extends Widget>> widgetSet =
73+
// reflections.getSubTypesOf(Widget.class);
74+
// Set<Class<?>> allClassSet = reflections.getSubTypesOf(Object.class);
75+
}
76+
77+
return widgetSet;
78+
}
79+
80+
/**
81+
* Return property information in a map
82+
*
83+
* @param prop
84+
* @return Map<information, value>
85+
*/
86+
private static Map<String, Object> getPropertyInformation(WidgetProperty<?> prop) {
87+
Map<String, Object> propInfo = new HashMap<>();
88+
if (prop != null) {
89+
propInfo.put(PropInformation.name.toString(), prop.getName());
90+
String description = prop.getDescription();
91+
if (description != null) {
92+
propInfo.put(PropInformation.description.toString(), description);
93+
}
94+
95+
// TODO Manage a long description
96+
97+
Object defaultValue = prop.getDefaultValue();
98+
if (defaultValue != null) {
99+
if (defaultValue.toString().contains("\n")) {
100+
defaultValue = defaultValue.toString().replace("\n", " ");
101+
}
102+
propInfo.put(PropInformation.defaultvalue.toString(), defaultValue);
103+
propInfo.put(PropInformation.type.toString(), defaultValue.getClass().getSimpleName());
104+
}
105+
106+
Object value = prop.getValue();
107+
if (value != null && !value.toString().contains("null") && !value.toString().isEmpty()) {
108+
if (value.toString().contains("\n")) {
109+
value = value.toString().replace("\n", " ");
110+
}
111+
propInfo.put(PropInformation.value.toString(), value);
112+
}
113+
114+
WidgetPropertyCategory category = prop.getCategory();
115+
if (category != null) {
116+
propInfo.put(PropInformation.category.toString(), category.name());
117+
}
118+
}
119+
return propInfo;
120+
}
121+
122+
/**
123+
* Return a map of widget Key classname Map of Property with value
124+
*/
125+
public static Map<String, Map<String, Map<String, Object>>> getAllWidgetInformations() {
126+
if (WIDGET_MAP.isEmpty()) {
127+
getAllWidgetInformations(null);
128+
//String packageName = Widget.class.getPackage().getName() + ".widgets";
129+
//getAllWidgetInformations(packageName);
130+
//getAllWidgetInformations(packageName + ".plots");
131+
}
132+
return WIDGET_MAP;
133+
}
134+
135+
private static void getAllWidgetInformations(String packageName) {
136+
Set<Class<? extends Widget>> widgetImplementations = getWidgetImplementations(packageName);
137+
Constructor<? extends Widget> declaredConstructor = null;
138+
Widget newInstance = null;
139+
Field descriptorField = null;
140+
141+
Map<String, Map<String, Object>> propInformationMap = null;
142+
Map<String, Object> propertyInfos = null;
143+
for (Class<? extends Widget> widgetClass : widgetImplementations) {
144+
try {
145+
descriptorField = widgetClass.getDeclaredField(WIDGET_DESCRIPTOR);
146+
} catch (Exception e) {
147+
// e.printStackTrace();
148+
}
149+
if (descriptorField != null && !Modifier.isAbstract(widgetClass.getModifiers())) {
150+
151+
try {
152+
declaredConstructor = widgetClass.getDeclaredConstructor();
153+
newInstance = declaredConstructor.newInstance();
154+
} catch (Exception e) {
155+
// System.out.println("widgetClass no empty constructor ");
156+
}
157+
158+
if (newInstance == null) {
159+
try {
160+
declaredConstructor = widgetClass.getDeclaredConstructor(String.class);
161+
newInstance = declaredConstructor.newInstance();
162+
} catch (Exception e) {
163+
e.printStackTrace();
164+
}
165+
}
166+
if (newInstance != null) {
167+
WidgetDescriptor descriptor = null;
168+
URL iconURL = null;
169+
try {
170+
Object object = descriptorField.get(newInstance);
171+
descriptor = ((WidgetDescriptor) object);
172+
iconURL = descriptor.getIconURL();
173+
} catch (Exception e) {
174+
// e.printStackTrace();
175+
}
176+
177+
if (iconURL != null && descriptor != null) {
178+
179+
propInformationMap = new HashMap<>();
180+
WIDGET_MAP.put(widgetClass.getSimpleName(), propInformationMap);
181+
// Add class
182+
propertyInfos = new HashMap<>();
183+
propertyInfos.put(PropInformation.name.toString(), PropInformation.java_class.toString());
184+
propertyInfos.put(PropInformation.type.toString(), String.class.getSimpleName());
185+
propertyInfos.put(PropInformation.description.toString(), "The java class of the widget");
186+
propertyInfos.put(PropInformation.value.toString(), widgetClass.getName());
187+
propInformationMap.put(PropInformation.java_class.toString(), propertyInfos);
188+
189+
// Add widget type
190+
propertyInfos = new HashMap<>();
191+
propertyInfos.put(PropInformation.name.toString(), PropInformation.widget_type.toString());
192+
propertyInfos.put(PropInformation.type.toString(), String.class.getSimpleName());
193+
propertyInfos.put(PropInformation.description.toString(), "The type of the widget");
194+
propertyInfos.put(PropInformation.value.toString(), descriptor.getType());
195+
propInformationMap.put(PropInformation.widget_type.toString(), propertyInfos);
196+
// Add Icon
197+
propertyInfos = new HashMap<>();
198+
propertyInfos.put(PropInformation.name.toString(), PropInformation.icon_url.toString());
199+
propertyInfos.put(PropInformation.type.toString(), String.class.getSimpleName());
200+
propertyInfos.put(PropInformation.description.toString(), "The url icon path");
201+
String file = iconURL.getPath();
202+
File iconFile = new File(file);
203+
propertyInfos.put(PropInformation.value.toString(), "images/" + iconFile.getName());
204+
propInformationMap.put(PropInformation.icon_url.toString(), propertyInfos);
205+
// Add version
206+
propertyInfos = new HashMap<>();
207+
propertyInfos.put(PropInformation.name.toString(), PropInformation.version.toString());
208+
propertyInfos.put(PropInformation.type.toString(), String.class.getSimpleName());
209+
propertyInfos.put(PropInformation.description.toString(), "The version of the widget");
210+
propertyInfos.put(PropInformation.value.toString(), newInstance.getVersion());
211+
propInformationMap.put(PropInformation.version.toString(), propertyInfos);
212+
213+
Set<WidgetProperty<?>> properties = newInstance.getProperties();
214+
if (properties != null) {
215+
for (WidgetProperty<?> prop : properties) {
216+
propertyInfos = getPropertyInformation(prop);
217+
propInformationMap.put(prop.getName(), propertyInfos);
218+
}
219+
}
220+
}
221+
}
222+
}
223+
}
224+
}
225+
226+
public static void generateAllWidgetRSTFile(String generateFilePath) {
227+
if (generateFilePath != null) {
228+
Map<String, Map<String, Map<String, Object>>> allWidgetInformations = getAllWidgetInformations();
229+
230+
Set<Entry<String, Map<String, Map<String, Object>>>> entrySet = allWidgetInformations.entrySet();
231+
String widgetName = null;
232+
Map<String, Map<String, Object>> propInfoMap = null;
233+
Collection<Map<String, Object>> propValues = null;
234+
// Set<Entry<String, Object>> propSet = null;
235+
File widgetDocument = new File(generateFilePath);
236+
237+
// String widgetDocPath =
238+
// "D:\\tmp\\Code\\Phoebus\\PhoebusWidgetInformations.txt";
239+
240+
// regenerate the makefile
241+
try ( // Try with resources in order to close at the end
242+
FileWriter fileWriter = new FileWriter(widgetDocument);
243+
BufferedWriter writer = new BufferedWriter(fileWriter);) {
244+
File parentFile = widgetDocument.getParentFile();
245+
// Create parent folder if not exist
246+
if (parentFile != null && !parentFile.exists()) {
247+
parentFile.mkdir();
248+
}
249+
250+
StringBuilder sb = new StringBuilder();
251+
sb.append("=====================================\n");
252+
sb.append("Widget List and Associated Properties\n");
253+
sb.append("=====================================\n\n");
254+
255+
for (Entry<String, Map<String, Map<String, Object>>> entry : entrySet) {
256+
widgetName = entry.getKey();
257+
propInfoMap = entry.getValue();
258+
propValues = propInfoMap.values();
259+
260+
sb.append(widgetName + "\n");
261+
sb.append("========================\n\n");
262+
263+
Map<String, Object> map = propInfoMap.get(PropInformation.icon_url.toString());
264+
sb.append(".. image:: " + map.get(PropInformation.value.toString()) + "\n");
265+
sb.append("\t:width: 30\n");
266+
sb.append("\t:alt: " + widgetName + "\n\n");
267+
map = propInfoMap.get(PropInformation.java_class.toString());
268+
sb.append("**Phoebus Class:** " + map.get(PropInformation.value.toString()) + "\n\n");
269+
map = propInfoMap.get(PropInformation.version.toString());
270+
sb.append("**Phoebus version:** " + map.get(PropInformation.value.toString()) + "\n\n");
271+
sb.append(".. list-table:: " + widgetName + " property list\n");
272+
sb.append("\t:header-rows: 1\n\n");
273+
sb.append("\t* - Name\n");
274+
sb.append("\t - Description\n");
275+
sb.append("\t - Type\n");
276+
sb.append("\t - Category\n");
277+
sb.append("\t - Value\n");
278+
sb.append("\t - DefaultValue\n");
279+
280+
for (Map<String, Object> propVal : propValues) {
281+
String propName = propVal.get(PropInformation.name.toString()).toString();
282+
Object cat = propVal.get(PropInformation.category.toString());
283+
if (cat != null) {
284+
sb.append("\t* - " + propName + "\n");
285+
sb.append("\t - " + propVal.get(PropInformation.description.toString()) + "\n");
286+
Object typeObject = propVal.get(PropInformation.type.toString());
287+
Object type = typeObject != null && !typeObject.toString().contains("null") ? typeObject
288+
: "";
289+
sb.append("\t - " + type + "\n");
290+
sb.append("\t - " + propVal.get(PropInformation.category.toString()) + "\n");
291+
Object valObject = propVal.get(PropInformation.value.toString());
292+
Object val = valObject != null && !valObject.toString().contains("null") ? valObject : "";
293+
sb.append("\t - " + val + "\n");
294+
Object defaultValObject = propVal.get(PropInformation.defaultvalue.toString());
295+
Object defaultVal = defaultValObject != null ? defaultValObject : "";
296+
sb.append("\t - " + defaultVal + "\n");
297+
}
298+
}
299+
sb.append("\n\n");
300+
301+
}
302+
303+
writer.write(sb.toString());
304+
System.out.println("Rst document generatation success " + generateFilePath);
305+
306+
} catch (Exception e) {
307+
System.err.println("Error during generation " + e.getMessage());
308+
}
309+
310+
}
311+
312+
}
313+
314+
public static void displayAllWidgetInfo() {
315+
Map<String, Map<String, Map<String, Object>>> allWidgetInformations = getAllWidgetInformations();
316+
317+
Set<Entry<String, Map<String, Map<String, Object>>>> entrySet = allWidgetInformations.entrySet();
318+
String widgetName = null;
319+
Map<String, Map<String, Object>> propInfoMap = null;
320+
Collection<Map<String, Object>> propValues = null;
321+
for (Entry<String, Map<String, Map<String, Object>>> entry : entrySet) {
322+
widgetName = entry.getKey();
323+
propInfoMap = entry.getValue();
324+
System.out.println("##### widget -> " + widgetName + "####");
325+
propValues = propInfoMap.values();
326+
for (Map<String, Object> propVal : propValues) {
327+
System.out.println(propVal);
328+
}
329+
}
330+
}
331+
332+
/**
333+
* Generate a rst document for all the widget and all the associated properties
334+
*
335+
* @param args the generated rst file
336+
*/
337+
public static void main(String[] args) {
338+
339+
String generateFilePath = args != null && args.length > 0 ? args[0] : null;
340+
341+
if (generateFilePath == null) {
342+
JFileChooser fileChooser = new JFileChooser();
343+
fileChooser.setMultiSelectionEnabled(false);
344+
fileChooser.setControlButtonsAreShown(true);
345+
fileChooser.setDialogTitle("Select a directory in which the widgets information file will be generate ");
346+
fileChooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
347+
JFrame frame = new JFrame();
348+
frame.setAlwaysOnTop(true);
349+
int showOpenDialog = fileChooser.showOpenDialog(frame);
350+
File selected = showOpenDialog == JFileChooser.APPROVE_OPTION ? fileChooser.getSelectedFile() : null;
351+
generateFilePath = selected != null ? selected.getAbsolutePath() + File.separator + "widgets_properties.rst"
352+
: null;
353+
}
354+
355+
if (generateFilePath != null) {
356+
generateAllWidgetRSTFile(generateFilePath);
357+
} else {
358+
System.err.println("No file or folder defined in argument");
359+
}
360+
361+
System.exit(0);
362+
}
363+
}

0 commit comments

Comments
 (0)