Starting from 2021-07-01, all LRZ GitLab users will be required to explicitly accept the GitLab Terms of Service. Please see the detailed information at https://doku.lrz.de/display/PUBLIC/GitLab and make sure that your projects conform to the requirements.

Commit bf8cca5d authored by Stefan Schuhbaeck's avatar Stefan Schuhbaeck
Browse files

Add help text annotation processor to show JavaDoc in GUI

parent 75ee4375
package org.vadere.annotation;
import java.util.HashSet;
import java.util.Set;
import javax.lang.model.element.ExecutableElement;
import javax.lang.model.element.TypeElement;
import javax.lang.model.element.TypeParameterElement;
import javax.lang.model.element.VariableElement;
import javax.lang.model.type.TypeKind;
import javax.lang.model.type.TypeMirror;
import javax.lang.model.util.ElementScanner7;
// see: https://stackoverflow.com/a/18777229
public class ImportScanner extends ElementScanner7<Void, Void> {
private Set<String> types = new HashSet<>();
public Set<String> getImportedTypes() {
return types;
}
@Override
public Void visitType(TypeElement e, Void p) {
for(TypeMirror interfaceType : e.getInterfaces()) {
types.add(interfaceType.toString());
}
types.add(e.getSuperclass().toString());
return super.visitType(e, p);
}
@Override
public Void visitExecutable(ExecutableElement e, Void p) {
if(e.getReturnType().getKind() == TypeKind.DECLARED) {
types.add(e.getReturnType().toString());
}
return super.visitExecutable(e, p);
}
@Override
public Void visitTypeParameter(TypeParameterElement e, Void p) {
if(e.asType().getKind() == TypeKind.DECLARED) {
types.add(e.asType().toString());
}
return super.visitTypeParameter(e, p);
}
@Override
public Void visitVariable(VariableElement e, Void p) {
if(e.asType().getKind() == TypeKind.DECLARED) {
types.add(e.asType().toString());
}
return super.visitVariable(e, p);
}
}
\ No newline at end of file
package org.vadere.annotation.helptext;
import com.google.auto.service.AutoService;
import org.vadere.annotation.ImportScanner;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Set;
import java.util.function.Function;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
import javax.annotation.processing.AbstractProcessor;
import javax.annotation.processing.Processor;
import javax.annotation.processing.RoundEnvironment;
import javax.annotation.processing.SupportedAnnotationTypes;
import javax.annotation.processing.SupportedSourceVersion;
import javax.lang.model.SourceVersion;
import javax.lang.model.element.Element;
import javax.lang.model.element.TypeElement;
import javax.tools.FileObject;
import javax.tools.StandardLocation;
@SupportedAnnotationTypes({"*"}) // run for all annotations. process must return false so annotations are not consumed
@SupportedSourceVersion(SourceVersion.RELEASE_11)
@AutoService(Processor.class)
public class HelpTextAnnotationProcessor extends AbstractProcessor {
ArrayList<Function<String, String>> pattern;
Set<String> importedTypes;
@Override
public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
initPattern();
ImportScanner scanner = new ImportScanner();
scanner.scan(roundEnv.getRootElements(), null);
importedTypes = scanner.getImportedTypes();
for (Element e: roundEnv.getRootElements()){
if (e.getKind().isClass() && e.asType().toString().startsWith("org.vadere.")) {
try {
String comment = processingEnv.getElementUtils().getDocComment(e);
String relname = buildHelpTextPath(e.asType().toString());
FileObject file = processingEnv.getFiler().createResource(StandardLocation.CLASS_OUTPUT, "", relname);
try (PrintWriter w = new PrintWriter(file.openWriter())) {
w.println("<h1> " + e.getSimpleName() + "</h1>");
w.println();
printComment(w, comment);
w.println();
printMemberDocString(e, w);
}
} catch (Exception ex) {
ex.printStackTrace();
}
}
}
return false; // allow further processing
}
private String buildHelpTextPath(String className) {
className = className.replace("<", "_");
className = className.replace(">", "_");
return "helpText/" + className + ".html";
}
private void initPattern() {
pattern = new ArrayList<>();
pattern.add( e -> {
Pattern r = Pattern.compile("(\\{@link\\s+#)(.*?)(})");
Matcher m = r.matcher(e);
while (m.find()){
e = m.replaceFirst("<span class='local_link'>$2</span>");
m = r.matcher(e);
}
return e;
});
pattern.add( e -> {
Pattern r = Pattern.compile("(\\{@link\\s+)(.*?)(})");
Matcher m = r.matcher(e);
while (m.find()){
String linkId = findFullPath(m.group(2));
e = m.replaceFirst(String.format("<a href='%s' class='class_link'>$2</a>", linkId));
m = r.matcher(e);
}
return e;
});
}
private String findFullPath(String className){
String n = importedTypes.stream().filter(e-> e.endsWith(className)).findFirst().orElse("rel_/"+className);
return "/helpText/" + n + ".html";
}
private void printComment(PrintWriter w, String multiLine){
if (multiLine == null){
w.println("<p>---</p>");
} else {
w.println("<p>");
multiLine.lines().map(String::strip).map(this::applyMatcher).forEach(w::println);
w.println("</p>");
}
}
private String applyMatcher(String line){
for(Function<String, String> p : pattern){
line = p.apply(line);
}
return line;
}
private void printMemberDocString(Element e, PrintWriter w) {
Set<? extends Element> fields = e.getEnclosedElements()
.stream()
.filter(o->o.getKind().isField())
.collect(Collectors.toSet());
for(Element field : fields){
w.println("<hr>");
w.println("<h2> Field: " + field.getSimpleName() + "</h2>");
String comment = processingEnv.getElementUtils().getDocComment(field);
printComment(w, comment);
w.println();
}
}
}
...@@ -377,6 +377,7 @@ Tab.Model.loadTemplateMenu.title=Load template ...@@ -377,6 +377,7 @@ Tab.Model.loadTemplateMenu.title=Load template
Tab.Model.confirmLoadTemplate.title=Continue? Tab.Model.confirmLoadTemplate.title=Continue?
Tab.Model.confirmLoadTemplate.text=This replaces the content of the text field. Tab.Model.confirmLoadTemplate.text=This replaces the content of the text field.
Tab.Model.addAttributesMenu.title=Add Attributes Tab.Model.addAttributesMenu.title=Add Attributes
Tab.Model.helpAttributesMenu.title=Help
Tab.Model.insertModelNameMenu.title=Insert model name Tab.Model.insertModelNameMenu.title=Insert model name
Tab.Model.insertModelNameSubMenu.title=Main models Tab.Model.insertModelNameSubMenu.title=Main models
Tab.Pedestrians.title=Pedestrians Tab.Pedestrians.title=Pedestrians
......
...@@ -367,6 +367,7 @@ Tab.Model.loadTemplateMenu.title=Voreinstellung laden ...@@ -367,6 +367,7 @@ Tab.Model.loadTemplateMenu.title=Voreinstellung laden
Tab.Model.confirmLoadTemplate.title=Fortfahren? Tab.Model.confirmLoadTemplate.title=Fortfahren?
Tab.Model.confirmLoadTemplate.text=Der Inhalt des Textfeldes wird ersetzt. Tab.Model.confirmLoadTemplate.text=Der Inhalt des Textfeldes wird ersetzt.
Tab.Model.addAttributesMenu.title=Attributes hinzuf\u00fcgen Tab.Model.addAttributesMenu.title=Attributes hinzuf\u00fcgen
Tab.Model.helpAttributesMenu.title=Hilfe
Tab.Model.insertModelNameMenu.title=Model-Name einf\u00fcgen Tab.Model.insertModelNameMenu.title=Model-Name einf\u00fcgen
Tab.Model.insertModelNameSubMenu.title=Hauptmodelle Tab.Model.insertModelNameSubMenu.title=Hauptmodelle
Tab.Pedestrians.title=Fu\u00dfg\u00e4nger Tab.Pedestrians.title=Fu\u00dfg\u00e4nger
......
package org.vadere.gui.components.control;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.ArrayList;
import javax.swing.*;
import javax.swing.event.HyperlinkEvent;
import javax.swing.text.Document;
import javax.swing.text.html.HTMLEditorKit;
import javax.swing.text.html.StyleSheet;
public class HelpTextView extends JEditorPane {
private ArrayList<String> filenames;
public static HelpTextView create(String className){
HelpTextView view = new HelpTextView();
view.loadHelpFromClass(className);
return view;
}
public HelpTextView() {
setContentType("text/html");
setEditable(false);
addHyperlinkListener(e -> {
if (e.getEventType() == HyperlinkEvent.EventType.ACTIVATED){
String link = e.getDescription();
if (link.startsWith("/helpText/rel_/")){
String clsName = link.split("/")[3].strip();
for(String f : filenames){
if (f.endsWith(clsName)){
link = f;
break;
}
}
}
loadHelpText(link);
}
});
filenames = new ArrayList<>();
try (
InputStream in = getClass().getResourceAsStream("/helpText");
BufferedReader br = new BufferedReader(new InputStreamReader(in))) {
String resource;
while ((resource = br.readLine()) != null) {
filenames.add(resource);
}
} catch (IOException e) {
e.printStackTrace();
}
}
public void loadHelpFromClass(String fullClassName){
loadHelpText("/helpText/" + fullClassName + ".html");
}
public void loadHelpText(String helpTextId){
System.out.println(helpTextId);
String text = null;
try {
InputStream url = getClass().getResourceAsStream(helpTextId);
text = new String(url.readAllBytes());
} catch (Exception ignored) {
text = "No Help found.";
}
HTMLEditorKit htmlEditorKit = new HTMLEditorKit();
StyleSheet sheet = htmlEditorKit.getStyleSheet();
sheet.addRule(".local_link {font-style: italic; text-decoration: underline;}");
sheet.addRule(".class_link {color: blue; font-style: italic; text-decoration: underline;}");
sheet.addRule("p { padding-bottom: 5px;}");
Document doc = htmlEditorKit.createDefaultDocument();
setDocument(doc);
setText(text);
}
}
...@@ -10,6 +10,7 @@ import org.vadere.gui.components.utils.Messages; ...@@ -10,6 +10,7 @@ import org.vadere.gui.components.utils.Messages;
import org.vadere.gui.components.view.JComboCheckBox; import org.vadere.gui.components.view.JComboCheckBox;
import org.vadere.gui.projectview.model.IScenarioChecker; import org.vadere.gui.projectview.model.IScenarioChecker;
import org.vadere.gui.projectview.utils.SimpleDocumentListener; import org.vadere.gui.projectview.utils.SimpleDocumentListener;
import org.vadere.gui.topographycreator.view.JLinkLabel;
import org.vadere.simulator.projects.Scenario; import org.vadere.simulator.projects.Scenario;
import org.vadere.simulator.projects.dataprocessing.DataProcessingJsonManager; import org.vadere.simulator.projects.dataprocessing.DataProcessingJsonManager;
import org.vadere.simulator.projects.dataprocessing.outputfile.OutputFile; import org.vadere.simulator.projects.dataprocessing.outputfile.OutputFile;
...@@ -636,7 +637,7 @@ class DataProcessingView extends JPanel implements IJsonView { ...@@ -636,7 +637,7 @@ class DataProcessingView extends JPanel implements IJsonView {
c.gridx = 0; c.gridx = 0;
c.gridy = 0; c.gridy = 0;
c.gridwidth = 3; c.gridwidth = 3;
panel.add(new JLabel("<html><b>" + dataProcessor.getSimpleProcessorTypeName() + "</b></html>"), c); panel.add(new JLinkLabel(dataProcessor.getClass().getName(), "<html><b>", "</b></html>"), c);
c.gridwidth = 1; c.gridwidth = 1;
c.gridx = 0; c.gridx = 0;
...@@ -645,7 +646,7 @@ class DataProcessingView extends JPanel implements IJsonView { ...@@ -645,7 +646,7 @@ class DataProcessingView extends JPanel implements IJsonView {
c.gridx = 1; c.gridx = 1;
c.gridy = 1; c.gridy = 1;
panel.add(new JLabel(extractSimpleName(getDataKeyForDataProcessor(dataProcessor))), c); panel.add(new JLinkLabel(getDataKeyForDataProcessor(dataProcessor).getTypeName()), c);
c.gridx = 2; c.gridx = 2;
c.gridy = 1; c.gridy = 1;
......
package org.vadere.gui.projectview.view; package org.vadere.gui.projectview.view;
import org.vadere.gui.components.control.HelpTextView;
import org.vadere.gui.components.utils.Messages; import org.vadere.gui.components.utils.Messages;
import org.vadere.gui.onlinevisualization.OnlineVisualization; import org.vadere.gui.onlinevisualization.OnlineVisualization;
import org.vadere.gui.postvisualization.view.PostvisualizationWindow; import org.vadere.gui.postvisualization.view.PostvisualizationWindow;
...@@ -156,6 +157,18 @@ public class ScenarioPanel extends JPanel implements IProjectChangeListener, Pro ...@@ -156,6 +157,18 @@ public class ScenarioPanel extends JPanel implements IProjectChangeListener, Pro
} }
} }
}))); })));
JMenu mnHelpAttributesMenu = new JMenu(Messages.getString("Tab.Model.helpAttributesMenu.title"));
presetMenuBar.add(mnHelpAttributesMenu);
menusInTabs.add(mnHelpAttributesMenu);
attributeFactory.sortedAttributeStream().forEach(
attributesClassName -> mnHelpAttributesMenu.add(new JMenuItem(new AbstractAction(attributesClassName) {
@Override
public void actionPerformed(ActionEvent e) {
VDialogManager.showMessageDialogWithBodyAndTextEditorPane("Help", attributesClassName,
HelpTextView.create(attributesClassName), JOptionPane.INFORMATION_MESSAGE);
}
})));
JMenu mnModelNameMenu = new JMenu(Messages.getString("Tab.Model.insertModelNameMenu.title")); JMenu mnModelNameMenu = new JMenu(Messages.getString("Tab.Model.insertModelNameMenu.title"));
presetMenuBar.add(mnModelNameMenu); presetMenuBar.add(mnModelNameMenu);
......
...@@ -8,6 +8,7 @@ import org.fife.ui.rsyntaxtextarea.SyntaxConstants; ...@@ -8,6 +8,7 @@ import org.fife.ui.rsyntaxtextarea.SyntaxConstants;
import org.fife.ui.rsyntaxtextarea.Theme; import org.fife.ui.rsyntaxtextarea.Theme;
import org.fife.ui.rtextarea.RTextScrollPane; import org.fife.ui.rtextarea.RTextScrollPane;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.vadere.gui.components.control.HelpTextView;
import org.vadere.gui.components.utils.Messages; import org.vadere.gui.components.utils.Messages;
import org.vadere.gui.components.utils.Resources; import org.vadere.gui.components.utils.Resources;
import org.vadere.gui.projectview.model.IScenarioChecker; import org.vadere.gui.projectview.model.IScenarioChecker;
...@@ -246,6 +247,20 @@ public class TextView extends JPanel implements IJsonView { ...@@ -246,6 +247,20 @@ public class TextView extends JPanel implements IJsonView {
} }
}))); })));
JMenu mnPresetHelpMenu = new JMenu(Messages.getString("ProjectView.mnHelp.text"));
presetMenuBar.add(mnPresetHelpMenu);
StimulusPresettings.PRESETTINGS_MAP.forEach(
(clazz, jsonString) -> mnPresetHelpMenu.add(new JMenuItem(new AbstractAction(clazz.getSimpleName()) {
private static final long serialVersionUID = 1L;
@Override
public void actionPerformed(ActionEvent e) {
VDialogManager.showMessageDialogWithBodyAndTextEditorPane("Help", clazz.getName(),
HelpTextView.create(clazz.getName()), JOptionPane.INFORMATION_MESSAGE);
}
})));
panelTop.add(presetMenuBar); panelTop.add(presetMenuBar);
} }
} }
......
package org.vadere.gui.topographycreator.view; package org.vadere.gui.topographycreator.view;
import java.awt.*;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.Observable; import java.util.Observable;
import java.util.Observer; import java.util.Observer;
import javax.swing.JLabel; import javax.swing.*;
import org.vadere.gui.components.control.HelpTextView;
import org.vadere.gui.components.utils.Messages; import org.vadere.gui.components.utils.Messages;
import org.vadere.gui.projectview.view.VDialogManager;
import org.vadere.gui.topographycreator.model.IDrawPanelModel; import org.vadere.gui.topographycreator.model.IDrawPanelModel;
import org.vadere.state.scenario.ScenarioElement; import org.vadere.state.scenario.ScenarioElement;
...@@ -15,11 +20,36 @@ public class JLabelObserver extends JLabel implements Observer { ...@@ -15,11 +20,36 @@ public class JLabelObserver extends JLabel implements Observer {
private static final long serialVersionUID = 9011952047793438028L; private static final long serialVersionUID = 9011952047793438028L;
private IDrawPanelModel panelModel; private IDrawPanelModel panelModel;
private String selectedElementAttrFQN;
public JLabelObserver(String labelText) { public JLabelObserver(String labelText) {
super(labelText); super(labelText);
setForeground(Color.BLUE.darker());
setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
addMouseListener(new MouseAdapter() {
@Override
public void mouseClicked(MouseEvent e) {
if (!selectedElementAttrFQN.equals("")){
String body = getText() + ": Help and Field Description";
VDialogManager.showMessageDialogWithBodyAndTextEditorPane("Help", body,
HelpTextView.create(selectedElementAttrFQN), JOptionPane.INFORMATION_MESSAGE);
}
}
@Override
public void mouseEntered(MouseEvent e) {
super.mouseEntered(e);
}
@Override
public void mouseExited(MouseEvent e) {
super.mouseExited(e);
}
});
} }
public void setPanelModel(IDrawPanelModel panelModel) { public void setPanelModel(IDrawPanelModel panelModel) {
this.panelModel = panelModel; this.panelModel = panelModel;
} }
...@@ -30,8 +60,12 @@ public class JLabelObserver extends JLabel implements Observer { ...@@ -30,8 +60,12 @@ public class JLabelObserver extends JLabel implements Observer {
ScenarioElement selectedElement = panelModel.getSelectedElement(); ScenarioElement selectedElement = panelModel.getSelectedElement();
String newText = DEFAULT_TEXT; String newText = DEFAULT_TEXT;
if (selectedElement != null) if (selectedElement != null){
newText = selectedElement.getClass().getSimpleName().toString(); newText = selectedElement.getClass().getSimpleName().toString();
selectedElementAttrFQN = selectedElement.getAttributes().getClass().getName();
} else {
selectedElementAttrFQN = "";
}
setText(newText); setText(newText);
} }
......
package org.vadere.gui.topographycreator.view;
import org.vadere.gui.components.control.HelpTextView;
import org.vadere.gui.projectview.view.VDialogManager;
import java.awt.*;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import javax.swing.*;
public class JLinkLabel extends JLabel {
private String fullName;
private String shortName;
public JLinkLabel(String fullName){
this(fullName, "", "");
}
public JLinkLabel(String fullName, String prefix, String suffix){
super();
this.fullName = fullName;
String[] tmp = fullName.split("\\.");
this.shortName = tmp[tmp.length-1];
setText(prefix + shortName + suffix);
setForeground(Color.BLUE.darker());
setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
addMouseListener(new MouseAdapter() {
@Override
public void mouseClicked(MouseEvent e) {
String body = shortName + ": Help and Field Description";
VDialogManager.showMessageDialogWithBodyAndTextEditorPane("Help", body,
HelpTextView.create(fullName), JOptionPane.INFORMATION_MESSAGE);
}
@Override
public void mouseEntered(MouseEvent e) {
super.mouseEntered(e);
}
@Override
public void mouseExited(MouseEvent e) {
super.mouseExited(e);
}
});
}
}
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment