Notice to GitKraken users: A vulnerability has been found in the SSH key generation of GitKraken versions 7.6.0 to 8.0.0 (https://www.gitkraken.com/blog/weak-ssh-key-fix). If you use GitKraken and have generated a SSH key using one of these versions, please remove it both from your local workstation and from your LRZ GitLab profile.

21.10.2021, 9:00 - 11:00: Due to updates GitLab may be unavailable for some minutes between 09:00 and 11:00.

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
Tab.Model.confirmLoadTemplate.title=Continue?
Tab.Model.confirmLoadTemplate.text=This replaces the content of the text field.
Tab.Model.addAttributesMenu.title=Add Attributes
Tab.Model.helpAttributesMenu.title=Help
Tab.Model.insertModelNameMenu.title=Insert model name
Tab.Model.insertModelNameSubMenu.title=Main models
Tab.Pedestrians.title=Pedestrians
......
......@@ -367,6 +367,7 @@ Tab.Model.loadTemplateMenu.title=Voreinstellung laden
Tab.Model.confirmLoadTemplate.title=Fortfahren?
Tab.Model.confirmLoadTemplate.text=Der Inhalt des Textfeldes wird ersetzt.
Tab.Model.addAttributesMenu.title=Attributes hinzuf\u00fcgen
Tab.Model.helpAttributesMenu.title=Hilfe
Tab.Model.insertModelNameMenu.title=Model-Name einf\u00fcgen
Tab.Model.insertModelNameSubMenu.title=Hauptmodelle
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;
import org.vadere.gui.components.view.JComboCheckBox;
import org.vadere.gui.projectview.model.IScenarioChecker;
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.dataprocessing.DataProcessingJsonManager;
import org.vadere.simulator.projects.dataprocessing.outputfile.OutputFile;
......@@ -636,7 +637,7 @@ class DataProcessingView extends JPanel implements IJsonView {
c.gridx = 0;
c.gridy = 0;
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.gridx = 0;
......@@ -645,7 +646,7 @@ class DataProcessingView extends JPanel implements IJsonView {
c.gridx = 1;
c.gridy = 1;
panel.add(new JLabel(extractSimpleName(getDataKeyForDataProcessor(dataProcessor))), c);
panel.add(new JLinkLabel(getDataKeyForDataProcessor(dataProcessor).getTypeName()), c);
c.gridx = 2;
c.gridy = 1;
......
package org.vadere.gui.projectview.view;
import org.vadere.gui.components.control.HelpTextView;
import org.vadere.gui.components.utils.Messages;
import org.vadere.gui.onlinevisualization.OnlineVisualization;
import org.vadere.gui.postvisualization.view.PostvisualizationWindow;
......@@ -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"));
presetMenuBar.add(mnModelNameMenu);
......
......@@ -8,6 +8,7 @@ import org.fife.ui.rsyntaxtextarea.SyntaxConstants;
import org.fife.ui.rsyntaxtextarea.Theme;
import org.fife.ui.rtextarea.RTextScrollPane;
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.Resources;
import org.vadere.gui.projectview.model.IScenarioChecker;
......@@ -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);
}
}
......
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.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.projectview.view.VDialogManager;
import org.vadere.gui.topographycreator.model.IDrawPanelModel;
import org.vadere.state.scenario.ScenarioElement;
......@@ -15,11 +20,36 @@ public class JLabelObserver extends JLabel implements Observer {
private static final long serialVersionUID = 9011952047793438028L;
private IDrawPanelModel panelModel;
private String selectedElementAttrFQN;
public JLabelObserver(String 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) {
this.panelModel = panelModel;
}
......@@ -30,8 +60,12 @@ public class JLabelObserver extends JLabel implements Observer {
ScenarioElement selectedElement = panelModel.getSelectedElement();
String newText = DEFAULT_TEXT;
if (selectedElement != null)
if (selectedElement != null){
newText = selectedElement.getClass().getSimpleName().toString();
selectedElementAttrFQN = selectedElement.getAttributes().getClass().getName();
} else {
selectedElementAttrFQN = "";
}
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