org.antlr.v4.gui.TreeViewer Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of antlr4 Show documentation
Show all versions of antlr4 Show documentation
The ANTLR 4 grammar compiler.
/*
* Copyright (c) 2012 The ANTLR Project. All rights reserved.
* Use of this file is governed by the BSD-3-Clause license that
* can be found in the LICENSE.txt file in the project root.
*/
package org.antlr.v4.gui;
import org.abego.treelayout.NodeExtentProvider;
import org.abego.treelayout.TreeForTreeLayout;
import org.abego.treelayout.TreeLayout;
import org.abego.treelayout.util.DefaultConfiguration;
import org.antlr.v4.runtime.ParserRuleContext;
import org.antlr.v4.runtime.misc.NotNull;
import org.antlr.v4.runtime.misc.Nullable;
import org.antlr.v4.runtime.misc.Utils;
import org.antlr.v4.runtime.tree.ErrorNode;
import org.antlr.v4.runtime.tree.Tree;
import org.antlr.v4.runtime.tree.Trees;
import javax.imageio.ImageIO;
import javax.print.PrintException;
import javax.swing.BorderFactory;
import javax.swing.Icon;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JDialog;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JSlider;
import javax.swing.JSplitPane;
import javax.swing.JTree;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import javax.swing.event.TreeSelectionEvent;
import javax.swing.event.TreeSelectionListener;
import javax.swing.filechooser.FileFilter;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.TreePath;
import javax.swing.tree.TreeSelectionModel;
import java.awt.BasicStroke;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.Container;
import java.awt.Desktop;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.awt.event.WindowListener;
import java.awt.geom.CubicCurve2D;
import java.awt.geom.Rectangle2D;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.FileWriter;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.Writer;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.prefs.Preferences;
@SuppressWarnings("serial")
public class TreeViewer extends JComponent {
public static final Color LIGHT_RED = new Color(244, 213, 211);
public static class DefaultTreeTextProvider implements TreeTextProvider {
private final List ruleNames;
public DefaultTreeTextProvider(@Nullable List ruleNames) {
this.ruleNames = ruleNames;
}
@Override
public String getText(Tree node) {
return String.valueOf(Trees.getNodeText(node, ruleNames));
}
}
public static class VariableExtentProvide implements NodeExtentProvider {
TreeViewer viewer;
public VariableExtentProvide(TreeViewer viewer) {
this.viewer = viewer;
}
@Override
public double getWidth(Tree tree) {
FontMetrics fontMetrics = viewer.getFontMetrics(viewer.font);
String s = viewer.getText(tree);
int w = fontMetrics.stringWidth(s) + viewer.nodeWidthPadding*2;
return w;
}
@Override
public double getHeight(Tree tree) {
FontMetrics fontMetrics = viewer.getFontMetrics(viewer.font);
int h = fontMetrics.getHeight() + viewer.nodeHeightPadding*2;
String s = viewer.getText(tree);
String[] lines = s.split("\n");
return h * lines.length;
}
}
protected TreeTextProvider treeTextProvider;
protected TreeLayout treeLayout;
protected java.util.List highlightedNodes;
protected String fontName = "Helvetica"; //Font.SANS_SERIF;
protected int fontStyle = Font.PLAIN;
protected int fontSize = 11;
protected Font font = new Font(fontName, fontStyle, fontSize);
protected double gapBetweenLevels = 17;
protected double gapBetweenNodes = 7;
protected int nodeWidthPadding = 2; // added to left/right
protected int nodeHeightPadding = 0; // added above/below
protected int arcSize = 0; // make an arc in node outline?
protected double scale = 1.0;
protected Color boxColor = null; // set to a color to make it draw background
protected Color highlightedBoxColor = Color.lightGray;
protected Color borderColor = null;
protected Color textColor = Color.black;
public TreeViewer(@Nullable List ruleNames, Tree tree) {
setRuleNames(ruleNames);
if ( tree!=null ) {
setTree(tree);
}
setFont(font);
}
private void updatePreferredSize() {
setPreferredSize(getScaledTreeSize());
invalidate();
if (getParent() != null) {
getParent().validate();
}
repaint();
}
// ---------------- PAINT -----------------------------------------------
private boolean useCurvedEdges = false;
public boolean getUseCurvedEdges() {
return useCurvedEdges;
}
public void setUseCurvedEdges(boolean useCurvedEdges) {
this.useCurvedEdges = useCurvedEdges;
}
protected void paintEdges(Graphics g, Tree parent) {
if (!getTree().isLeaf(parent)) {
BasicStroke stroke = new BasicStroke(1.0f, BasicStroke.CAP_ROUND,
BasicStroke.JOIN_ROUND);
((Graphics2D)g).setStroke(stroke);
Rectangle2D.Double parentBounds = getBoundsOfNode(parent);
double x1 = parentBounds.getCenterX();
double y1 = parentBounds.getMaxY();
for (Tree child : getTree().getChildren(parent)) {
Rectangle2D.Double childBounds = getBoundsOfNode(child);
double x2 = childBounds.getCenterX();
double y2 = childBounds.getMinY();
if (getUseCurvedEdges()) {
CubicCurve2D c = new CubicCurve2D.Double();
double ctrlx1 = x1;
double ctrly1 = (y1+y2)/2;
double ctrlx2 = x2;
double ctrly2 = y1;
c.setCurve(x1, y1, ctrlx1, ctrly1, ctrlx2, ctrly2, x2, y2);
((Graphics2D) g).draw(c);
}
else {
g.drawLine((int) x1, (int) y1,
(int) x2, (int) y2);
}
paintEdges(g, child);
}
}
}
protected void paintBox(Graphics g, Tree tree) {
Rectangle2D.Double box = getBoundsOfNode(tree);
// draw the box in the background
boolean ruleFailedAndMatchedNothing = false;
if ( tree instanceof ParserRuleContext ) {
ParserRuleContext ctx = (ParserRuleContext) tree;
ruleFailedAndMatchedNothing = ctx.exception != null &&
ctx.stop != null && ctx.stop.getTokenIndex() < ctx.start.getTokenIndex();
}
if ( isHighlighted(tree) || boxColor!=null ||
tree instanceof ErrorNode ||
ruleFailedAndMatchedNothing)
{
if ( isHighlighted(tree) ) g.setColor(highlightedBoxColor);
else if ( tree instanceof ErrorNode || ruleFailedAndMatchedNothing ) g.setColor(LIGHT_RED);
else g.setColor(boxColor);
g.fillRoundRect((int) box.x, (int) box.y, (int) box.width - 1,
(int) box.height - 1, arcSize, arcSize);
}
if ( borderColor!=null ) {
g.setColor(borderColor);
g.drawRoundRect((int) box.x, (int) box.y, (int) box.width - 1,
(int) box.height - 1, arcSize, arcSize);
}
// draw the text on top of the box (possibly multiple lines)
g.setColor(textColor);
String s = getText(tree);
String[] lines = s.split("\n");
FontMetrics m = getFontMetrics(font);
int x = (int) box.x + arcSize / 2 + nodeWidthPadding;
int y = (int) box.y + m.getAscent() + m.getLeading() + 1 + nodeHeightPadding;
for (int i = 0; i < lines.length; i++) {
text(g, lines[i], x, y);
y += m.getHeight();
}
}
public void text(Graphics g, String s, int x, int y) {
// System.out.println("drawing '"+s+"' @ "+x+","+y);
s = Utils.escapeWhitespace(s, true);
g.drawString(s, x, y);
}
@Override
public void paint(Graphics g) {
super.paint(g);
if ( treeLayout==null ) {
return;
}
Graphics2D g2 = (Graphics2D)g;
// anti-alias the lines
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
// Anti-alias the text
g2.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING,
RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
// AffineTransform at = g2.getTransform();
// g2.scale(
// (double) this.getWidth() / 400,
// (double) this.getHeight() / 400);
//
// g2.setTransform(at);
paintEdges(g, getTree().getRoot());
// paint the boxes
for (Tree Tree : treeLayout.getNodeBounds().keySet()) {
paintBox(g, Tree);
}
}
protected void generateEdges(Writer writer, Tree parent) throws IOException {
if (!getTree().isLeaf(parent)) {
Rectangle2D.Double b1 = getBoundsOfNode(parent);
double x1 = b1.getCenterX();
double y1 = b1.getCenterY();
for (Tree child : getTree().getChildren(parent)) {
Rectangle2D.Double childBounds = getBoundsOfNode(child);
double x2 = childBounds.getCenterX();
double y2 = childBounds.getMinY();
writer.write(line(""+x1, ""+y1, ""+x2, ""+y2,
"stroke:black; stroke-width:1px;"));
generateEdges(writer, child);
}
}
}
protected void generateBox(Writer writer, Tree parent) throws IOException {
// draw the box in the background
Rectangle2D.Double box = getBoundsOfNode(parent);
writer.write(rect(""+box.x, ""+box.y, ""+box.width, ""+box.height,
"fill:orange; stroke:rgb(0,0,0);", "rx=\"1\""));
// draw the text on top of the box (possibly multiple lines)
String line = getText(parent).replace("<","<").replace(">",">");
int fontSize = 10;
int x = (int) box.x + 2;
int y = (int) box.y + fontSize - 1;
String style = String.format("font-family:sans-serif;font-size:%dpx;",
fontSize);
writer.write(text(""+x, ""+y, style, line));
}
private static String line(String x1, String y1, String x2, String y2,
String style) {
return String
.format(" \n",
x1, y1, x2, y2, style);
}
private static String rect(String x, String y, String width, String height,
String style, String extraAttributes) {
return String
.format(" \n",
x, y, width, height, style, extraAttributes);
}
private static String text(String x, String y, String style, String text) {
return String.format(
"\n%s\n \n", x, y,
style, text);
}
private void paintSVG(Writer writer) throws IOException {
generateEdges(writer, getTree().getRoot());
for (Tree tree : treeLayout.getNodeBounds().keySet()) {
generateBox(writer, tree);
}
}
@Override
protected Graphics getComponentGraphics(Graphics g) {
Graphics2D g2d=(Graphics2D)g;
g2d.scale(scale, scale);
return super.getComponentGraphics(g2d);
}
// ----------------------------------------------------------------------
private static final String DIALOG_WIDTH_PREFS_KEY = "dialog_width";
private static final String DIALOG_HEIGHT_PREFS_KEY = "dialog_height";
private static final String DIALOG_X_PREFS_KEY = "dialog_x";
private static final String DIALOG_Y_PREFS_KEY = "dialog_y";
private static final String DIALOG_DIVIDER_LOC_PREFS_KEY = "dialog_divider_location";
private static final String DIALOG_VIEWER_SCALE_PREFS_KEY = "dialog_viewer_scale";
@NotNull
protected static JDialog showInDialog(final TreeViewer viewer) {
final JDialog dialog = new JDialog();
dialog.setTitle("Parse Tree Inspector");
final Preferences prefs = Preferences.userNodeForPackage(TreeViewer.class);
// Make new content panes
final Container mainPane = new JPanel(new BorderLayout(5,5));
final Container contentPane = new JPanel(new BorderLayout(0,0));
contentPane.setBackground(Color.white);
// Wrap viewer in scroll pane
JScrollPane scrollPane = new JScrollPane(viewer);
// Make the scrollpane (containing the viewer) the center component
contentPane.add(scrollPane, BorderLayout.CENTER);
JPanel wrapper = new JPanel(new FlowLayout());
// Add button to bottom
JPanel bottomPanel = new JPanel(new BorderLayout(0,0));
contentPane.add(bottomPanel, BorderLayout.SOUTH);
JButton ok = new JButton("OK");
ok.addActionListener(
new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
dialog.dispatchEvent(new WindowEvent(dialog, WindowEvent.WINDOW_CLOSING));
}
}
);
wrapper.add(ok);
// Add an export-to-png button right of the "OK" button
JButton png = new JButton("Export as PNG");
png.addActionListener(
new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
generatePNGFile(viewer, dialog);
}
}
);
wrapper.add(png);
// Add an export-to-png button right of the "OK" button
JButton svg = new JButton("Export as SVG");
svg.addActionListener(
new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
generateSVGFile(viewer, dialog);
}
}
);
wrapper.add(svg);
bottomPanel.add(wrapper, BorderLayout.SOUTH);
// Add scale slider
double lastKnownViewerScale = prefs.getDouble(DIALOG_VIEWER_SCALE_PREFS_KEY, viewer.getScale());
viewer.setScale(lastKnownViewerScale);
int sliderValue = (int) ((lastKnownViewerScale - 1.0) * 1000);
final JSlider scaleSlider = new JSlider(JSlider.HORIZONTAL, -999, 1000, sliderValue);
scaleSlider.addChangeListener(
new ChangeListener() {
@Override
public void stateChanged(ChangeEvent e) {
int v = scaleSlider.getValue();
viewer.setScale(v / 1000.0 + 1.0);
}
}
);
bottomPanel.add(scaleSlider, BorderLayout.CENTER);
// Add a JTree representing the parser tree of the input.
JPanel treePanel = new JPanel(new BorderLayout(5, 5));
// An "empty" icon that will be used for the JTree's nodes.
Icon empty = new EmptyIcon();
UIManager.put("Tree.closedIcon", empty);
UIManager.put("Tree.openIcon", empty);
UIManager.put("Tree.leafIcon", empty);
Tree parseTreeRoot = viewer.getTree().getRoot();
TreeNodeWrapper nodeRoot = new TreeNodeWrapper(parseTreeRoot, viewer);
fillTree(nodeRoot, parseTreeRoot, viewer);
final JTree tree = new JTree(nodeRoot);
tree.getSelectionModel().setSelectionMode(TreeSelectionModel.SINGLE_TREE_SELECTION);
tree.addTreeSelectionListener(new TreeSelectionListener() {
@Override
public void valueChanged(TreeSelectionEvent e) {
JTree selectedTree = (JTree) e.getSource();
TreePath path = selectedTree.getSelectionPath();
if (path!=null) {
TreeNodeWrapper treeNode = (TreeNodeWrapper) path.getLastPathComponent();
// Set the clicked AST.
viewer.setTree((Tree) treeNode.getUserObject());
}
}
});
treePanel.add(new JScrollPane(tree));
// Create the pane for both the JTree and the AST
final JSplitPane splitPane = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT,
treePanel, contentPane);
mainPane.add(splitPane, BorderLayout.CENTER);
dialog.setContentPane(mainPane);
// make viz
WindowListener exitListener = new WindowAdapter() {
@Override
public void windowClosing(WindowEvent e) {
prefs.putInt(DIALOG_WIDTH_PREFS_KEY, (int) dialog.getSize().getWidth());
prefs.putInt(DIALOG_HEIGHT_PREFS_KEY, (int) dialog.getSize().getHeight());
prefs.putDouble(DIALOG_X_PREFS_KEY, dialog.getLocationOnScreen().getX());
prefs.putDouble(DIALOG_Y_PREFS_KEY, dialog.getLocationOnScreen().getY());
prefs.putInt(DIALOG_DIVIDER_LOC_PREFS_KEY, splitPane.getDividerLocation());
prefs.putDouble(DIALOG_VIEWER_SCALE_PREFS_KEY, viewer.getScale());
dialog.setVisible(false);
dialog.dispose();
}
};
dialog.addWindowListener(exitListener);
dialog.setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
int width = prefs.getInt(DIALOG_WIDTH_PREFS_KEY, 600);
int height = prefs.getInt(DIALOG_HEIGHT_PREFS_KEY, 500);
dialog.setPreferredSize(new Dimension(width, height));
dialog.pack();
// After pack(): set the divider at 1/3 (200/600) of the frame.
int dividerLocation = prefs.getInt(DIALOG_DIVIDER_LOC_PREFS_KEY, 200);
splitPane.setDividerLocation(dividerLocation);
if (prefs.getDouble(DIALOG_X_PREFS_KEY, -1) != -1) {
dialog.setLocation(
(int)prefs.getDouble(DIALOG_X_PREFS_KEY, 100),
(int)prefs.getDouble(DIALOG_Y_PREFS_KEY, 100)
);
}
else {
dialog.setLocationRelativeTo(null);
}
dialog.setVisible(true);
return dialog;
}
private static void generatePNGFile(TreeViewer viewer, JDialog dialog) {
BufferedImage bi = new BufferedImage(viewer.getSize().width,
viewer.getSize().height,
BufferedImage.TYPE_INT_ARGB);
Graphics g = bi.createGraphics();
viewer.paint(g);
g.dispose();
try {
JFileChooser fileChooser = getFileChooser(".png", "PNG files");
int returnValue = fileChooser.showSaveDialog(dialog);
if (returnValue == JFileChooser.APPROVE_OPTION) {
File pngFile = fileChooser.getSelectedFile();
ImageIO.write(bi, "png", pngFile);
try {
// Try to open the parent folder using the OS' native file manager.
Desktop.getDesktop().open(pngFile.getParentFile());
}
catch (Exception ex) {
// We could not launch the file manager: just show a popup that we
// succeeded in saving the PNG file.
JOptionPane.showMessageDialog(dialog, "Saved PNG to: " +
pngFile.getAbsolutePath());
ex.printStackTrace();
}
}
}
catch (Exception ex) {
JOptionPane.showMessageDialog(dialog,
"Could not export to PNG: " + ex.getMessage(),
"Error",
JOptionPane.ERROR_MESSAGE);
ex.printStackTrace();
}
}
private static JFileChooser getFileChooser(final String fileEnding,
final String description) {
File suggestedFile = generateNonExistingFile(fileEnding);
JFileChooser fileChooser = new JFileChooserConfirmOverwrite();
fileChooser.setCurrentDirectory(suggestedFile.getParentFile());
fileChooser.setSelectedFile(suggestedFile);
FileFilter filter = new FileFilter() {
@Override
public boolean accept(File pathname) {
if (pathname.isFile()) {
return pathname.getName().toLowerCase().endsWith(fileEnding);
}
return true;
}
@Override
public String getDescription() {
return description+" (*"+fileEnding+")";
}
};
fileChooser.addChoosableFileFilter(filter);
fileChooser.setFileFilter(filter);
return fileChooser;
}
private static void generateSVGFile(TreeViewer viewer, JDialog dialog) {
try {
JFileChooser fileChooser = getFileChooser(".svg", "SVG files");
int returnValue = fileChooser.showSaveDialog(dialog);
if (returnValue == JFileChooser.APPROVE_OPTION) {
File svgFile = fileChooser.getSelectedFile();
// save the new svg file here!
BufferedWriter writer = new BufferedWriter(new FileWriter(svgFile));
// HACK: multiplying with 1.1 should be replaced wit an accurate number
writer.write("");
writer.flush();
writer.close();
try {
// Try to open the parent folder using the OS' native file manager.
Desktop.getDesktop().open(svgFile.getParentFile());
} catch (Exception ex) {
// We could not launch the file manager: just show a popup that we
// succeeded in saving the PNG file.
JOptionPane.showMessageDialog(dialog, "Saved SVG to: "
+ svgFile.getAbsolutePath());
ex.printStackTrace();
}
}
} catch (Exception ex) {
JOptionPane.showMessageDialog(dialog,
"Could not export to SVG: " + ex.getMessage(),
"Error",
JOptionPane.ERROR_MESSAGE);
ex.printStackTrace();
}
}
private static File generateNonExistingFile(String extension) {
final String parent = ".";
final String name = "antlr4_parse_tree";
File file = new File(parent, name + extension);
int counter = 1;
// Keep looping until we create a File that does not yet exist.
while (file.exists()) {
file = new File(parent, name + "_" + counter + extension);
counter++;
}
return file;
}
private static void fillTree(TreeNodeWrapper node, Tree tree, TreeViewer viewer) {
if (tree == null) {
return;
}
for (int i = 0; i < tree.getChildCount(); i++) {
Tree childTree = tree.getChild(i);
TreeNodeWrapper childNode = new TreeNodeWrapper(childTree, viewer);
node.add(childNode);
fillTree(childNode, childTree, viewer);
}
}
private Dimension getScaledTreeSize() {
Dimension scaledTreeSize =
treeLayout.getBounds().getBounds().getSize();
scaledTreeSize = new Dimension((int)(scaledTreeSize.width*scale),
(int)(scaledTreeSize.height*scale));
return scaledTreeSize;
}
@NotNull
public Future open() {
final TreeViewer viewer = this;
viewer.setScale(1.5);
Callable callable = new Callable() {
JDialog result;
@Override
public JDialog call() throws Exception {
SwingUtilities.invokeAndWait(new Runnable() {
@Override
public void run() {
result = showInDialog(viewer);
}
});
return result;
}
};
ExecutorService executor = Executors.newSingleThreadExecutor();
try {
return executor.submit(callable);
}
finally {
executor.shutdown();
}
}
public void save(String fileName) throws IOException, PrintException {
JDialog dialog = new JDialog();
Container contentPane = dialog.getContentPane();
((JComponent) contentPane).setBorder(BorderFactory.createEmptyBorder(
10, 10, 10, 10));
contentPane.add(this);
contentPane.setBackground(Color.white);
dialog.pack();
dialog.setLocationRelativeTo(null);
dialog.dispose();
GraphicsSupport.saveImage(this, fileName);
}
// ---------------------------------------------------
protected Rectangle2D.Double getBoundsOfNode(Tree node) {
return treeLayout.getNodeBounds().get(node);
}
protected String getText(Tree tree) {
String s = treeTextProvider.getText(tree);
s = Utils.escapeWhitespace(s, true);
return s;
}
public TreeTextProvider getTreeTextProvider() {
return treeTextProvider;
}
public void setTreeTextProvider(TreeTextProvider treeTextProvider) {
this.treeTextProvider = treeTextProvider;
}
public void setFontSize(int sz) {
fontSize = sz;
font = new Font(fontName, fontStyle, fontSize);
}
public void setFontName(String name) {
fontName = name;
font = new Font(fontName, fontStyle, fontSize);
}
/** Slow for big lists of highlighted nodes */
public void addHighlightedNodes(Collection nodes) {
highlightedNodes = new ArrayList();
highlightedNodes.addAll(nodes);
}
public void removeHighlightedNodes(Collection nodes) {
if ( highlightedNodes!=null ) {
// only remove exact objects defined by ==, not equals()
for (Tree t : nodes) {
int i = getHighlightedNodeIndex(t);
if ( i>=0 ) highlightedNodes.remove(i);
}
}
}
protected boolean isHighlighted(Tree node) {
return getHighlightedNodeIndex(node) >= 0;
}
protected int getHighlightedNodeIndex(Tree node) {
if ( highlightedNodes==null ) return -1;
for (int i = 0; i < highlightedNodes.size(); i++) {
Tree t = highlightedNodes.get(i);
if ( t == node ) return i;
}
return -1;
}
@Override
public Font getFont() {
return font;
}
@Override
public void setFont(Font font) {
this.font = font;
}
public int getArcSize() {
return arcSize;
}
public void setArcSize(int arcSize) {
this.arcSize = arcSize;
}
public Color getBoxColor() {
return boxColor;
}
public void setBoxColor(Color boxColor) {
this.boxColor = boxColor;
}
public Color getHighlightedBoxColor() {
return highlightedBoxColor;
}
public void setHighlightedBoxColor(Color highlightedBoxColor) {
this.highlightedBoxColor = highlightedBoxColor;
}
public Color getBorderColor() {
return borderColor;
}
public void setBorderColor(Color borderColor) {
this.borderColor = borderColor;
}
public Color getTextColor() {
return textColor;
}
public void setTextColor(Color textColor) {
this.textColor = textColor;
}
protected TreeForTreeLayout getTree() {
return treeLayout.getTree();
}
public void setTree(Tree root) {
if ( root!=null ) {
boolean useIdentity = true; // compare node identity
this.treeLayout =
new TreeLayout(getTreeLayoutAdaptor(root),
new TreeViewer.VariableExtentProvide(this),
new DefaultConfiguration(gapBetweenLevels,
gapBetweenNodes),
useIdentity);
// Let the UI display this new AST.
updatePreferredSize();
}
else {
this.treeLayout = null;
repaint();
}
}
/** Get an adaptor for root that indicates how to walk ANTLR trees.
* Override to change the adapter from the default of {@link TreeLayoutAdaptor} */
public TreeForTreeLayout getTreeLayoutAdaptor(Tree root) {
return new TreeLayoutAdaptor(root);
}
public double getScale() {
return scale;
}
public void setScale(double scale) {
if(scale <= 0) {
scale = 1;
}
this.scale = scale;
updatePreferredSize();
}
public void setRuleNames(List ruleNames) {
setTreeTextProvider(new DefaultTreeTextProvider(ruleNames));
}
private static class TreeNodeWrapper extends DefaultMutableTreeNode {
final TreeViewer viewer;
TreeNodeWrapper(Tree tree, TreeViewer viewer) {
super(tree);
this.viewer = viewer;
}
@Override
public String toString() {
return viewer.getText((Tree) this.getUserObject());
}
}
private static class EmptyIcon implements Icon {
@Override
public int getIconWidth() {
return 0;
}
@Override
public int getIconHeight() {
return 0;
}
@Override
public void paintIcon(Component c, Graphics g, int x, int y) {
/* Do nothing. */
}
}
}