fixed graph test issue (and a few other improviements)> Mainly protecting against creating ridiculously large icons in tests because of a strange headless environment.

This commit is contained in:
ghidravore 2021-08-18 12:28:12 -04:00
parent 5e5d474279
commit 1fd6b54f07
6 changed files with 149 additions and 75 deletions

View file

@ -94,7 +94,6 @@ public class DefaultGraphDisplay implements GraphDisplay {
private static final String ACTION_OWNER = "GraphServices"; private static final String ACTION_OWNER = "GraphServices";
private static final int MAX_NODES = Integer.getInteger("maxNodes", 10000);
private static final Dimension PREFERRED_VIEW_SIZE = new Dimension(1000, 1000); private static final Dimension PREFERRED_VIEW_SIZE = new Dimension(1000, 1000);
private static final Dimension PREFERRED_LAYOUT_SIZE = new Dimension(3000, 3000); private static final Dimension PREFERRED_LAYOUT_SIZE = new Dimension(3000, 3000);
@ -273,16 +272,16 @@ public class DefaultGraphDisplay implements GraphDisplay {
Lens lens = Lens.builder().lensShape(Lens.Shape.RECTANGLE).magnification(3.f).build(); Lens lens = Lens.builder().lensShape(Lens.Shape.RECTANGLE).magnification(3.f).build();
lens.setMagnification(2.f); lens.setMagnification(2.f);
LensMagnificationGraphMousePlugin magnificationPlugin = LensMagnificationGraphMousePlugin magnificationPlugin =
new LensMagnificationGraphMousePlugin(1.f, 60.f, .2f) { new LensMagnificationGraphMousePlugin(1.f, 60.f, .2f) {
// Override to address a bug when using a high resolution mouse wheel. // Override to address a bug when using a high resolution mouse wheel.
// May be removed when jungrapht-visualization version is updated // May be removed when jungrapht-visualization version is updated
@Override @Override
public void mouseWheelMoved(MouseWheelEvent e) { public void mouseWheelMoved(MouseWheelEvent e) {
if (e.getWheelRotation() != 0) { if (e.getWheelRotation() != 0) {
super.mouseWheelMoved(e); super.mouseWheelMoved(e);
}
} }
}; }
};
MutableTransformer transformer = viewer.getRenderContext() MutableTransformer transformer = viewer.getRenderContext()
.getMultiLayerTransformer() .getMultiLayerTransformer()
@ -1158,9 +1157,10 @@ public class DefaultGraphDisplay implements GraphDisplay {
this.title = title; this.title = title;
componentProvider.setTitle(title); componentProvider.setTitle(title);
int count = graph.getVertexCount(); int count = graph.getVertexCount();
if (count > MAX_NODES) { if (count > options.getMaxNodeCount()) {
Msg.showWarn(this, null, "Graph Not Rendered - Too many nodes!", Msg.showWarn(this, null, "Graph Not Rendered - Too many nodes!",
"Exceeded limit of " + MAX_NODES + " nodes.\n\n Graph contained " + count + "Exceeded limit of " + options.getMaxNodeCount() + " nodes.\n\n Graph contained " +
count +
" nodes!"); " nodes!");
graph = new AttributedGraph("Aborted", graph.getGraphType(), "Too Many Nodes"); graph = new AttributedGraph("Aborted", graph.getGraphType(), "Too Many Nodes");
graph.addVertex("1", "Graph Aborted"); graph.addVertex("1", "Graph Aborted");

View file

@ -47,8 +47,18 @@ public class DefaultGraphRenderer implements GraphRenderer {
private static final double ARROW_WIDTH_TO_LENGTH_RATIO = 1.3; private static final double ARROW_WIDTH_TO_LENGTH_RATIO = 1.3;
private static final int DEFAULT_MARGIN_BORDER_SIZE = 4; private static final int DEFAULT_MARGIN_BORDER_SIZE = 4;
private static final int DEFAULT_STROKE_THICKNESS = 6; private static final int DEFAULT_STROKE_THICKNESS = 6;
// scale factor so the icons can be rendered smaller so that fonts read better when zoomed out a bit
private static final int ICON_ZOOM = 5; // This is an arbitrary scale factor applied after creating a node's icon
// This somehow causes the low level jungrapht layout to perform better
// If the icon is not zoomed, the icons are rendered too small and too far apart
// somehow, by giving it bigger icons, the layouts seem to produce better results
// When/if this is fixed in the jungrapht library, this can be removed
private static final int ICON_ZOOM = 2;
// put a limit on node size. Nodes are sized based on user supplied vertex names, so need to
// protect them from becoming too large, so just picked some limits.
private static final int MAX_WIDTH = 500;
private static final int MAX_HEIGHT = 500;
private int labelBorderSize = DEFAULT_MARGIN_BORDER_SIZE; private int labelBorderSize = DEFAULT_MARGIN_BORDER_SIZE;
private int strokeThickness = DEFAULT_STROKE_THICKNESS; private int strokeThickness = DEFAULT_STROKE_THICKNESS;
@ -220,7 +230,6 @@ public class DefaultGraphRenderer implements GraphRenderer {
VertexShape vertexShape = options.getVertexShape(vertex); VertexShape vertexShape = options.getVertexShape(vertex);
Color vertexColor = options.getVertexColor(vertex); Color vertexColor = options.getVertexColor(vertex);
String labelText = options.getVertexLabel(vertex); String labelText = options.getVertexLabel(vertex);
return createImage(vertexShape, labelText, vertexColor); return createImage(vertexShape, labelText, vertexColor);
} }
@ -235,37 +244,47 @@ public class DefaultGraphRenderer implements GraphRenderer {
Shape unitShape = vertexShape.getShape(); Shape unitShape = vertexShape.getShape();
Rectangle bounds = unitShape.getBounds(); Rectangle bounds = unitShape.getBounds();
// this variable attempts to keep the shape's height from being too out of proportion
// from the width.
int maxWidthToHeightRatio = vertexShape.getMaxWidthToHeightRatio(); int maxWidthToHeightRatio = vertexShape.getMaxWidthToHeightRatio();
double sizeFactor = vertexShape.getShapeToLabelRatio(); double sizeFactor = vertexShape.getShapeToLabelRatio();
int labelWidth = label.getWidth(); int labelWidth = label.getWidth();
int labelHeight = label.getHeight(); int labelHeight = label.getHeight();
int iconWidth = // make height somewhat bigger if label width is really long to avoid really long thin
(int) (Math.max(labelWidth, labelHeight * 2.0) * sizeFactor) + strokeThickness; // nodes
int iconHeight = labelHeight = Math.max(labelHeight, labelWidth / maxWidthToHeightRatio);
(int) (Math.max(label.getHeight(), labelWidth / maxWidthToHeightRatio) * sizeFactor) +
strokeThickness;
double scalex = iconWidth / bounds.getWidth(); // adjust for shape size factor (some shapes want to be somewhat bigger than the label)
double scaley = iconHeight / bounds.getHeight(); // for example, triangles need to be much bigger to get the text to fit inside the shape,
// whereas, rectangles fit naturally.
int shapeWidth = (int) (labelWidth * sizeFactor);
int shapeHeight = (int) (labelHeight * sizeFactor);
// compute the amount to scale the shape to fit around the label
double scalex = shapeWidth / bounds.getWidth();
double scaley = shapeHeight / bounds.getHeight();
Shape scaledShape = Shape scaledShape =
AffineTransform.getScaleInstance(scalex, scaley).createTransformedShape(unitShape); AffineTransform.getScaleInstance(scalex, scaley).createTransformedShape(unitShape);
// this determines the vertical positioning of text in the shape
// a value of 0 will put the text at the top, 1 at the bottom, and .5 in the center
double labelOffsetRatio = vertexShape.getLabelPosition(); double labelOffsetRatio = vertexShape.getLabelPosition();
bounds = scaledShape.getBounds(); bounds = scaledShape.getBounds();
int iconWidth = bounds.width + (2 * strokeThickness);
int iconHeight = bounds.height + (2 * strokeThickness);
int width = bounds.width + 2 * strokeThickness; BufferedImage bufferedImage =
int height = bounds.height + strokeThickness; new BufferedImage(iconWidth, iconHeight, BufferedImage.TYPE_INT_ARGB);
BufferedImage bufferedImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
Graphics2D graphics = bufferedImage.createGraphics(); Graphics2D graphics = bufferedImage.createGraphics();
graphics.setRenderingHints(renderingHints); graphics.setRenderingHints(renderingHints);
AffineTransform graphicsTransform = graphics.getTransform(); AffineTransform graphicsTransform = graphics.getTransform();
graphics.translate(-bounds.x + strokeThickness, -bounds.y + strokeThickness / 2); // shapes are centered at the origin, so translate the graphics to compensate
graphics.translate(-bounds.x + strokeThickness, -bounds.y + strokeThickness);
graphics.setPaint(Color.WHITE); graphics.setPaint(Color.WHITE);
graphics.fill(scaledShape); graphics.fill(scaledShape);
graphics.setPaint(vertexColor); graphics.setPaint(vertexColor);
@ -273,8 +292,12 @@ public class DefaultGraphRenderer implements GraphRenderer {
graphics.draw(scaledShape); graphics.draw(scaledShape);
graphics.setTransform(graphicsTransform); graphics.setTransform(graphicsTransform);
int xOffset = (width - label.getWidth()) / 2;
int yOffset = (int) ((height - label.getHeight()) * labelOffsetRatio); // center the text horizontally
// position the text vertically based on the shape.
int xOffset = (iconWidth - label.getWidth()) / 2;
int yOffset = (int) ((iconHeight - label.getHeight()) * labelOffsetRatio);
graphics.translate(xOffset, yOffset); graphics.translate(xOffset, yOffset);
graphics.setPaint(Color.black); graphics.setPaint(Color.black);
label.paint(graphics); label.paint(graphics);
@ -282,19 +305,26 @@ public class DefaultGraphRenderer implements GraphRenderer {
graphics.setTransform(graphicsTransform); // restore the original transform graphics.setTransform(graphicsTransform); // restore the original transform
graphics.dispose(); graphics.dispose();
Image scaledImage = Image scaledImage =
ImageUtils.createScaledImage(bufferedImage, width * ICON_ZOOM, height * ICON_ZOOM, ImageUtils.createScaledImage(bufferedImage, iconWidth * ICON_ZOOM,
iconHeight * ICON_ZOOM,
Image.SCALE_FAST); Image.SCALE_FAST);
ImageIcon imageIcon = new ImageIcon(scaledImage); ImageIcon imageIcon = new ImageIcon(scaledImage);
return imageIcon; return imageIcon;
} }
private void prepareLabel(String vertexName, Color vertexColor) { private void prepareLabel(String vertexName, Color vertexColor) {
label.setFont(options.getFont()); // The label is just used as a renderer and never parented, so no need to be
// on the swing thread
Font font = options.getFont();
label.setFont(font);
label.setText(vertexName); label.setText(vertexName);
Dimension labelSize = label.getPreferredSize(); Dimension labelSize = label.getPreferredSize();
label.setSize(labelSize);
// make sure the the vertexName doesn't make the icon ridiculously big
int width = Math.min(labelSize.width, MAX_WIDTH);
int height = Math.min(labelSize.height, MAX_HEIGHT);
label.setSize(width, height);
} }
@Override @Override

View file

@ -39,10 +39,10 @@ import ghidra.util.bean.opteditor.OptionsVetoException;
* and edge type and shapes for vertex types. * and edge type and shapes for vertex types.
*/ */
public class GraphDisplayOptions implements OptionsChangeListener { public class GraphDisplayOptions implements OptionsChangeListener {
public static final GraphDisplayOptions DEFAULT = public static final GraphDisplayOptions DEFAULT =
new GraphDisplayOptions(new EmptyGraphType()); new GraphDisplayOptions(new EmptyGraphType());
private static final String FONT = "Font"; private static final String FONT = "Font";
private static final String LABEL_POSITION = "Label Position"; private static final String LABEL_POSITION = "Label Position";
private static final String USE_ICONS = "Use Icons"; private static final String USE_ICONS = "Use Icons";
@ -50,7 +50,7 @@ public class GraphDisplayOptions implements OptionsChangeListener {
private static final String EDGE_COLORS = "Edge Colors"; private static final String EDGE_COLORS = "Edge Colors";
private static final String VERTEX_COLORS = "Vertex Colors"; private static final String VERTEX_COLORS = "Vertex Colors";
private static final String VERTEX_SHAPES = "Vertex Shapes"; private static final String VERTEX_SHAPES = "Vertex Shapes";
private static final String MISCELLANIOUS_OPTIONS = "Miscellanious"; private static final String MISCELLANEOUS_OPTIONS = "Miscellaneous";
private static final String DEFAULT_VERTEX_COLOR = "Default Vertex Color"; private static final String DEFAULT_VERTEX_COLOR = "Default Vertex Color";
private static final String DEFAULT_EDGE_COLOR = "Default Edge Color"; private static final String DEFAULT_EDGE_COLOR = "Default Edge Color";
private static final String DEFAULT_VERTEX_SHAPE = "Default Vertex Shape"; private static final String DEFAULT_VERTEX_SHAPE = "Default Vertex Shape";
@ -58,6 +58,8 @@ public class GraphDisplayOptions implements OptionsChangeListener {
private static final String VERTEX_SELECTION_COLOR = "Selected Vertex Color"; private static final String VERTEX_SELECTION_COLOR = "Selected Vertex Color";
private static final String EDGE_SELECTION_COLOR = "Selected Edge Color"; private static final String EDGE_SELECTION_COLOR = "Selected Edge Color";
private static final String MAX_NODES_SIZE = "Max Graph Size";
private GraphType graphType; private GraphType graphType;
private Map<String, Color> vertexColorMap = new HashMap<>(); private Map<String, Color> vertexColorMap = new HashMap<>();
@ -85,6 +87,8 @@ public class GraphDisplayOptions implements OptionsChangeListener {
private Font font = new Font("Dialog", Font.BOLD, 18); private Font font = new Font("Dialog", Font.BOLD, 18);
private int arrowLength = 15; private int arrowLength = 15;
private int maxNodeCount = 500; // graph display struggles with too many nodes
/** /**
* Constructs a new GraphTypeDisplayOptions for the given {@link GraphType} * Constructs a new GraphTypeDisplayOptions for the given {@link GraphType}
* @param graphType The {@link GraphType} for which to define display options * @param graphType The {@link GraphType} for which to define display options
@ -139,8 +143,6 @@ public class GraphDisplayOptions implements OptionsChangeListener {
changeListeners.remove(listener); changeListeners.remove(listener);
} }
/** /**
* Sets the default shape to be used by vertices that don't have a vertex type set * Sets the default shape to be used by vertices that don't have a vertex type set
* @param shape the default vertex shape * @param shape the default vertex shape
@ -384,7 +386,6 @@ public class GraphDisplayOptions implements OptionsChangeListener {
vertexShapeMap.put(vertexType, Objects.requireNonNull(vertexShape)); vertexShapeMap.put(vertexType, Objects.requireNonNull(vertexShape));
} }
/** /**
* Returns the color for the given edge type * Returns the color for the given edge type
* @param edgeType the edge type whose color is to be determined. * @param edgeType the edge type whose color is to be determined.
@ -579,6 +580,24 @@ public class GraphDisplayOptions implements OptionsChangeListener {
this.arrowLength = length; this.arrowLength = length;
} }
/**
* Returns the maximum number of nodes that can be in a displayed graph
* @return the maximum number of nodes that can be in a displayed graph
*/
public int getMaxNodeCount() {
return maxNodeCount;
}
/**
* Sets the maximum number of nodes a graph can have and still be displayed. Be careful,
* setting this value too high can result in Ghidra running out of memory and/or
* making the system very sluggish.
* @param maxNodeCount the maximum number of nodes a graph can have and still be displayed.
*/
public void setMaxNodeCount(int maxNodeCount) {
this.maxNodeCount = maxNodeCount;
}
/** /**
* Returns true if this {@link GraphDisplayOptions} instance has been constructed with * Returns true if this {@link GraphDisplayOptions} instance has been constructed with
* a tool for getting/saving option values in the tool options * a tool for getting/saving option values in the tool options
@ -603,7 +622,7 @@ public class GraphDisplayOptions implements OptionsChangeListener {
registerVertexColorOptions(rootOptions, help); registerVertexColorOptions(rootOptions, help);
registerVertexShapeOptions(rootOptions, help); registerVertexShapeOptions(rootOptions, help);
registerEdgeColorOptions(rootOptions, help); registerEdgeColorOptions(rootOptions, help);
registerMiscellaniousOptions(rootOptions, help); registerMiscellaneousOptions(rootOptions, help);
} }
/** /**
@ -643,7 +662,6 @@ public class GraphDisplayOptions implements OptionsChangeListener {
registeredWithTool = true; registeredWithTool = true;
} }
private void updateOptions(Options rootOptions) { private void updateOptions(Options rootOptions) {
updateVertexColorsFromOptions(rootOptions); updateVertexColorsFromOptions(rootOptions);
updateEdgeColorsFromOptions(rootOptions); updateEdgeColorsFromOptions(rootOptions);
@ -652,7 +670,7 @@ public class GraphDisplayOptions implements OptionsChangeListener {
} }
private void updateMiscellaniousOptions(Options rootOptions) { private void updateMiscellaniousOptions(Options rootOptions) {
Options options = rootOptions.getOptions(MISCELLANIOUS_OPTIONS); Options options = rootOptions.getOptions(MISCELLANEOUS_OPTIONS);
String shapeName = options.getString(DEFAULT_VERTEX_SHAPE, defaultVertexShape.getName()); String shapeName = options.getString(DEFAULT_VERTEX_SHAPE, defaultVertexShape.getName());
defaultVertexShape = VertexShape.getShape(shapeName); defaultVertexShape = VertexShape.getShape(shapeName);
@ -662,13 +680,14 @@ public class GraphDisplayOptions implements OptionsChangeListener {
vertexSelectionColor = options.getColor(VERTEX_SELECTION_COLOR, vertexSelectionColor); vertexSelectionColor = options.getColor(VERTEX_SELECTION_COLOR, vertexSelectionColor);
edgeSelectionColor = options.getColor(EDGE_SELECTION_COLOR, edgeSelectionColor); edgeSelectionColor = options.getColor(EDGE_SELECTION_COLOR, edgeSelectionColor);
defaultLayoutAlgorithmName = defaultLayoutAlgorithmName =
options.getString(DEFAULT_LAYOUT_ALGORITHM, defaultLayoutAlgorithmName); options.getString(DEFAULT_LAYOUT_ALGORITHM, defaultLayoutAlgorithmName);
useIcons = options.getBoolean(USE_ICONS, useIcons); useIcons = options.getBoolean(USE_ICONS, useIcons);
labelPosition = options.getEnum(LABEL_POSITION, labelPosition); labelPosition = options.getEnum(LABEL_POSITION, labelPosition);
font = options.getFont(FONT, font); font = options.getFont(FONT, font);
maxNodeCount = options.getInt(MAX_NODES_SIZE, maxNodeCount);
} }
private void updateVertexShapesFromOptions(Options rootOptions) { private void updateVertexShapesFromOptions(Options rootOptions) {
@ -713,7 +732,6 @@ public class GraphDisplayOptions implements OptionsChangeListener {
} }
} }
private void registerVertexColorOptions(Options rootOptions, HelpLocation help) { private void registerVertexColorOptions(Options rootOptions, HelpLocation help) {
Options options = rootOptions.getOptions(VERTEX_COLORS); Options options = rootOptions.getOptions(VERTEX_COLORS);
@ -755,10 +773,12 @@ public class GraphDisplayOptions implements OptionsChangeListener {
options.registerOptionsEditor(editor); options.registerOptionsEditor(editor);
} }
private void registerMiscellaniousOptions(Options rootOptions, HelpLocation help) { private void registerMiscellaneousOptions(Options rootOptions, HelpLocation help) {
Options options = rootOptions.getOptions(MISCELLANIOUS_OPTIONS); Options options = rootOptions.getOptions(MISCELLANEOUS_OPTIONS);
options.registerOption(MAX_NODES_SIZE, OptionType.INT_TYPE, maxNodeCount, help,
"Graphs with more than this number of nodes will not be displayed. (Large graphs can cause Ghidra to become unstable/sluggish)");
StringWithChoicesEditor editor = new StringWithChoicesEditor(VertexShape.getShapeNames()); StringWithChoicesEditor editor = new StringWithChoicesEditor(VertexShape.getShapeNames());
options.registerOption(VERTEX_SELECTION_COLOR, OptionType.COLOR_TYPE, vertexSelectionColor, options.registerOption(VERTEX_SELECTION_COLOR, OptionType.COLOR_TYPE, vertexSelectionColor,
@ -777,9 +797,12 @@ public class GraphDisplayOptions implements OptionsChangeListener {
options.registerOption(DEFAULT_EDGE_COLOR, OptionType.COLOR_TYPE, defaultEdgeColor, options.registerOption(DEFAULT_EDGE_COLOR, OptionType.COLOR_TYPE, defaultEdgeColor,
help, "Color for edge that have no edge type defined"); help, "Color for edge that have no edge type defined");
editor = new StringWithChoicesEditor(graphType.getEdgeTypes()); List<String> edgeTypes = graphType.getEdgeTypes();
options.registerOption(FAVORED_EDGE_TYPE, OptionType.STRING_TYPE, favoredEdgeType, help, if (!edgeTypes.isEmpty()) {
"Favored edge is used to influence layout algorithms", editor); editor = new StringWithChoicesEditor(edgeTypes);
options.registerOption(FAVORED_EDGE_TYPE, OptionType.STRING_TYPE, favoredEdgeType, help,
"Favored edge is used to influence layout algorithms", editor);
}
editor = new StringWithChoicesEditor(LayoutAlgorithmNames.getLayoutAlgorithmNames()); editor = new StringWithChoicesEditor(LayoutAlgorithmNames.getLayoutAlgorithmNames());
options.registerOption(DEFAULT_LAYOUT_ALGORITHM, OptionType.STRING_TYPE, options.registerOption(DEFAULT_LAYOUT_ALGORITHM, OptionType.STRING_TYPE,
@ -796,6 +819,7 @@ public class GraphDisplayOptions implements OptionsChangeListener {
List<String> optionNamesInDisplayOrder = new ArrayList<>(); List<String> optionNamesInDisplayOrder = new ArrayList<>();
optionNamesInDisplayOrder.add(MAX_NODES_SIZE);
optionNamesInDisplayOrder.add(VERTEX_SELECTION_COLOR); optionNamesInDisplayOrder.add(VERTEX_SELECTION_COLOR);
optionNamesInDisplayOrder.add(EDGE_SELECTION_COLOR); optionNamesInDisplayOrder.add(EDGE_SELECTION_COLOR);
optionNamesInDisplayOrder.add(DEFAULT_VERTEX_COLOR); optionNamesInDisplayOrder.add(DEFAULT_VERTEX_COLOR);
@ -807,9 +831,8 @@ public class GraphDisplayOptions implements OptionsChangeListener {
optionNamesInDisplayOrder.add(FONT); optionNamesInDisplayOrder.add(FONT);
optionNamesInDisplayOrder.add(USE_ICONS); optionNamesInDisplayOrder.add(USE_ICONS);
OptionsEditor optionsEditor = OptionsEditor optionsEditor =
new ScrollableOptionsEditor(MISCELLANIOUS_OPTIONS, optionNamesInDisplayOrder); new ScrollableOptionsEditor(MISCELLANEOUS_OPTIONS, optionNamesInDisplayOrder);
options.registerOptionsEditor(optionsEditor); options.registerOptionsEditor(optionsEditor);
} }
@ -827,5 +850,5 @@ public class GraphDisplayOptions implements OptionsChangeListener {
"\" not defined in GraphType \"" + getGraphType().getName() + "\"."); "\" not defined in GraphType \"" + getGraphType().getName() + "\".");
} }
} }
}
}

View file

@ -26,7 +26,7 @@ public class GraphDisplayOptionsBuilder {
private GraphDisplayOptions displayOptions; private GraphDisplayOptions displayOptions;
/** /**
* Create a new {@link GraphDisplayOptionsBuilder} * Create a new GraphDisplayOptionsBuilder
* @param graphType the {@link GraphType} of graphs that this instance configures. * @param graphType the {@link GraphType} of graphs that this instance configures.
*/ */
public GraphDisplayOptionsBuilder(GraphType graphType) { public GraphDisplayOptionsBuilder(GraphType graphType) {
@ -36,7 +36,7 @@ public class GraphDisplayOptionsBuilder {
/** /**
* Sets the default vertex color for vertexes that don't have a registered vertex type * Sets the default vertex color for vertexes that don't have a registered vertex type
* @param c the default vertex color * @param c the default vertex color
* @return this {@link GraphDisplayOptionsBuilder} * @return this GraphDisplayOptionsBuilder
*/ */
public GraphDisplayOptionsBuilder defaultVertexColor(Color c) { public GraphDisplayOptionsBuilder defaultVertexColor(Color c) {
displayOptions.setDefaultVertexColor(c); displayOptions.setDefaultVertexColor(c);
@ -46,7 +46,7 @@ public class GraphDisplayOptionsBuilder {
/** /**
* Sets the default edge color for edges that don't have a registered edge type * Sets the default edge color for edges that don't have a registered edge type
* @param c the default edge color * @param c the default edge color
* @return this {@link GraphDisplayOptionsBuilder} * @return this GraphDisplayOptionsBuilder
*/ */
public GraphDisplayOptionsBuilder defaultEdgeColor(Color c) { public GraphDisplayOptionsBuilder defaultEdgeColor(Color c) {
Objects.requireNonNull(c); Objects.requireNonNull(c);
@ -57,7 +57,7 @@ public class GraphDisplayOptionsBuilder {
/** /**
* Sets the vertex selection color * Sets the vertex selection color
* @param color the vertex selection color * @param color the vertex selection color
* @return this {@link GraphDisplayOptionsBuilder} * @return this GraphDisplayOptionsBuilder
*/ */
public GraphDisplayOptionsBuilder vertexSelectionColor(Color color) { public GraphDisplayOptionsBuilder vertexSelectionColor(Color color) {
displayOptions.setVertexSelectionColor(color); displayOptions.setVertexSelectionColor(color);
@ -67,7 +67,7 @@ public class GraphDisplayOptionsBuilder {
/** /**
* Sets the edge selection color * Sets the edge selection color
* @param color the edge selection color * @param color the edge selection color
* @return this {@link GraphDisplayOptionsBuilder} * @return this GraphDisplayOptionsBuilder
*/ */
public GraphDisplayOptionsBuilder edgeSelectionColor(Color color) { public GraphDisplayOptionsBuilder edgeSelectionColor(Color color) {
displayOptions.setEdgeSelectionColor(color); displayOptions.setEdgeSelectionColor(color);
@ -77,7 +77,7 @@ public class GraphDisplayOptionsBuilder {
/** /**
* Sets the default vertex shape for vertices that don't have a registered vertex type * Sets the default vertex shape for vertices that don't have a registered vertex type
* @param vertexShape the {@link VertexShape} to use as a default * @param vertexShape the {@link VertexShape} to use as a default
* @return this {@link GraphDisplayOptionsBuilder} * @return this GraphDisplayOptionsBuilder
*/ */
public GraphDisplayOptionsBuilder defaultVertexShape(VertexShape vertexShape) { public GraphDisplayOptionsBuilder defaultVertexShape(VertexShape vertexShape) {
Objects.requireNonNull(vertexShape); Objects.requireNonNull(vertexShape);
@ -90,7 +90,7 @@ public class GraphDisplayOptionsBuilder {
* @param vertexType the vertex type to assign shape and color * @param vertexType the vertex type to assign shape and color
* @param vertexShape the shape to use for the named vertex type * @param vertexShape the shape to use for the named vertex type
* @param color the color to use for the named vertex type * @param color the color to use for the named vertex type
* @return this {@link GraphDisplayOptionsBuilder} * @return this GraphDisplayOptionsBuilder
*/ */
public GraphDisplayOptionsBuilder vertex(String vertexType, VertexShape vertexShape, public GraphDisplayOptionsBuilder vertex(String vertexType, VertexShape vertexShape,
Color color) { Color color) {
@ -102,7 +102,7 @@ public class GraphDisplayOptionsBuilder {
* Sets the color for edges of the given type * Sets the color for edges of the given type
* @param edgeType the edge type to assign color * @param edgeType the edge type to assign color
* @param color the color to use for the named edge type * @param color the color to use for the named edge type
* @return this {@link GraphDisplayOptionsBuilder} * @return this GraphDisplayOptionsBuilder
*/ */
public GraphDisplayOptionsBuilder edge(String edgeType, Color color) { public GraphDisplayOptionsBuilder edge(String edgeType, Color color) {
displayOptions.configureEdgeType(edgeType, color); displayOptions.configureEdgeType(edgeType, color);
@ -112,7 +112,7 @@ public class GraphDisplayOptionsBuilder {
/** /**
* Sets the attribute used to override the color for a vertex * Sets the attribute used to override the color for a vertex
* @param colorAttributeKey the attribute key to use for overriding a vertex color * @param colorAttributeKey the attribute key to use for overriding a vertex color
* @return this {@link GraphDisplayOptionsBuilder} * @return this GraphDisplayOptionsBuilder
*/ */
public GraphDisplayOptionsBuilder vertexColorOverrideAttribute(String colorAttributeKey) { public GraphDisplayOptionsBuilder vertexColorOverrideAttribute(String colorAttributeKey) {
displayOptions.setVertexColorOverrideAttributeKey(colorAttributeKey); displayOptions.setVertexColorOverrideAttributeKey(colorAttributeKey);
@ -122,7 +122,7 @@ public class GraphDisplayOptionsBuilder {
/** /**
* Sets the attribute used to override the color for a edge * Sets the attribute used to override the color for a edge
* @param colorAttributeKey the attribute key to use for overriding an edge color * @param colorAttributeKey the attribute key to use for overriding an edge color
* @return this {@link GraphDisplayOptionsBuilder} * @return this GraphDisplayOptionsBuilder
*/ */
public GraphDisplayOptionsBuilder edgeColorOverrideAttribute(String colorAttributeKey) { public GraphDisplayOptionsBuilder edgeColorOverrideAttribute(String colorAttributeKey) {
displayOptions.setEdgeColorOverrideAttributeKey(colorAttributeKey); displayOptions.setEdgeColorOverrideAttributeKey(colorAttributeKey);
@ -132,7 +132,7 @@ public class GraphDisplayOptionsBuilder {
/** /**
* Sets the attribute used to override the shape for a vertex * Sets the attribute used to override the shape for a vertex
* @param shapeAttributeKey the attribute key to use of shape override * @param shapeAttributeKey the attribute key to use of shape override
* @return this {@link GraphDisplayOptionsBuilder} * @return this GraphDisplayOptionsBuilder
*/ */
public GraphDisplayOptionsBuilder shapeOverrideAttribute(String shapeAttributeKey) { public GraphDisplayOptionsBuilder shapeOverrideAttribute(String shapeAttributeKey) {
displayOptions.setVertexShapeOverrideAttributeKey(shapeAttributeKey); displayOptions.setVertexShapeOverrideAttributeKey(shapeAttributeKey);
@ -142,7 +142,7 @@ public class GraphDisplayOptionsBuilder {
/** /**
* Sets the name of the layout algorithm that will be used to initially layout the graph * Sets the name of the layout algorithm that will be used to initially layout the graph
* @param string the name of the layout algoritm to use to initially layout the graph * @param string the name of the layout algoritm to use to initially layout the graph
* @return this {@link GraphDisplayOptionsBuilder} * @return this GraphDisplayOptionsBuilder
*/ */
public GraphDisplayOptionsBuilder defaultLayoutAlgorithm(String string) { public GraphDisplayOptionsBuilder defaultLayoutAlgorithm(String string) {
displayOptions.setDefaultLayoutAlgorithmName(string); displayOptions.setDefaultLayoutAlgorithmName(string);
@ -154,7 +154,7 @@ public class GraphDisplayOptionsBuilder {
* cached images with the label inside the shapes. If false, vertices are drawn as smaller * cached images with the label inside the shapes. If false, vertices are drawn as smaller
* shapes with labels drawn near the shapes. * shapes with labels drawn near the shapes.
* @param b true to use pre-rendered icon images * @param b true to use pre-rendered icon images
* @return this {@link GraphDisplayOptionsBuilder} * @return this GraphDisplayOptionsBuilder
*/ */
public GraphDisplayOptionsBuilder useIcons(boolean b) { public GraphDisplayOptionsBuilder useIcons(boolean b) {
displayOptions.setUsesIcons(b); displayOptions.setUsesIcons(b);
@ -164,18 +164,28 @@ public class GraphDisplayOptionsBuilder {
/** /**
* Sets the length of the arrows to display in the graph. The width will be sized proportionately. * Sets the length of the arrows to display in the graph. The width will be sized proportionately.
* @param length the length the arrows to display in the graph * @param length the length the arrows to display in the graph
* @return this {@link GraphDisplayOptionsBuilder} * @return this GraphDisplayOptionsBuilder
*/ */
public GraphDisplayOptionsBuilder arrowLength(int length) { public GraphDisplayOptionsBuilder arrowLength(int length) {
displayOptions.setArrowLength(length); displayOptions.setArrowLength(length);
return this; return this;
} }
/**
* Sets the maximum number of nodes a graph can have and still be displayed.
* @param maxNodeCount the maximum number of nodes
* @return this GraphDisplayOptionsBuilder
*/
public GraphDisplayOptionsBuilder maxNodeCount(int maxNodeCount) {
displayOptions.getMaxNodeCount();
return this;
}
/** /**
* Sets the vertex label position relative to vertex shape. This is only applicable if the * Sets the vertex label position relative to vertex shape. This is only applicable if the
* {@link #useIcons(boolean)} is set to true. * {@link #useIcons(boolean)} is set to false.
* @param labelPosition the relative position to place the vertex label * @param labelPosition the relative position to place the vertex label
* @return this {@link GraphDisplayOptionsBuilder} * @return this GraphDisplayOptionsBuilder
*/ */
public GraphDisplayOptionsBuilder labelPosition(GraphLabelPosition labelPosition) { public GraphDisplayOptionsBuilder labelPosition(GraphLabelPosition labelPosition) {
displayOptions.setLabelPosition(labelPosition); displayOptions.setLabelPosition(labelPosition);

View file

@ -37,8 +37,8 @@ public class GraphDisplayOptionsTest {
@Before @Before
public void setUp() { public void setUp() {
List<String> vertexTypes = Arrays.asList("V1", "V2", "V3" ); List<String> vertexTypes = Arrays.asList("V1", "V2", "V3");
List<String> edgeTypes = Arrays.asList("E1", "E2", "E3" ); List<String> edgeTypes = Arrays.asList("E1", "E2", "E3");
graphType = new GraphType("Test", "Test Description", vertexTypes, edgeTypes); graphType = new GraphType("Test", "Test Description", vertexTypes, edgeTypes);
options = new GraphDisplayOptions(graphType); options = new GraphDisplayOptions(graphType);
} }
@ -217,7 +217,6 @@ public class GraphDisplayOptionsTest {
assertEquals(VertexShape.STAR, options.getVertexShape("V1")); assertEquals(VertexShape.STAR, options.getVertexShape("V1"));
} }
@Test @Test
public void testGetEdgeColorForType() { public void testGetEdgeColorForType() {
assertEquals(options.getDefaultEdgeColor(), options.getEdgeColor("V1")); assertEquals(options.getDefaultEdgeColor(), options.getEdgeColor("V1"));
@ -252,8 +251,8 @@ public class GraphDisplayOptionsTest {
assertEquals(options.getDefaultEdgeColor(), assertEquals(options.getDefaultEdgeColor(),
edgeColorOptions.getColor("E1", Color.WHITE)); edgeColorOptions.getColor("E1", Color.WHITE));
Options miscellaniousOptions = graphDisplayOptions.getOptions("Miscellanious"); Options miscellaneousOptions = graphDisplayOptions.getOptions("Miscellaneous");
leafOptionNames = miscellaniousOptions.getLeafOptionNames(); leafOptionNames = miscellaneousOptions.getLeafOptionNames();
assertEquals(Arrays.asList("Use Icons", "Selected Vertex Color", "Default Layout Algorithm", assertEquals(Arrays.asList("Use Icons", "Selected Vertex Color", "Default Layout Algorithm",
"Default Vertex Color", "Default Vertex Shape", "Selected Edge Color", "Label Position", "Default Vertex Color", "Default Vertex Shape", "Selected Edge Color", "Label Position",
"Default Edge Color", "Font", "Favored Edge Type"), leafOptionNames); "Default Edge Color", "Font", "Favored Edge Type"), leafOptionNames);

View file

@ -33,6 +33,7 @@ import ghidra.graph.visualization.GroupVertex;
import ghidra.service.graph.*; import ghidra.service.graph.*;
import ghidra.test.AbstractGhidraHeadedIntegrationTest; import ghidra.test.AbstractGhidraHeadedIntegrationTest;
import ghidra.test.TestEnv; import ghidra.test.TestEnv;
import ghidra.util.exception.CancelledException;
import ghidra.util.task.TaskMonitor; import ghidra.util.task.TaskMonitor;
public class GraphActionsTest extends AbstractGhidraHeadedIntegrationTest { public class GraphActionsTest extends AbstractGhidraHeadedIntegrationTest {
@ -445,7 +446,18 @@ public class GraphActionsTest extends AbstractGhidraHeadedIntegrationTest {
GraphDisplayBroker broker = tool.getService(GraphDisplayBroker.class); GraphDisplayBroker broker = tool.getService(GraphDisplayBroker.class);
GraphDisplayProvider service = broker.getGraphDisplayProvider("Default Graph Display"); GraphDisplayProvider service = broker.getGraphDisplayProvider("Default Graph Display");
display = service.getGraphDisplay(false, TaskMonitor.DUMMY); display = service.getGraphDisplay(false, TaskMonitor.DUMMY);
display.setGraph(graph, "test graph", false, TaskMonitor.DUMMY); GraphDisplayOptions options = new GraphDisplayOptions(graph.getGraphType());
runSwing(() -> {
try {
display.setGraph(graph, options, "test graph", false, TaskMonitor.DUMMY);
}
catch (CancelledException e) {
// can't happen with a dummy monitor
}
});
display.setGraphDisplayListener(new TestGraphDisplayListener("test")); display.setGraphDisplayListener(new TestGraphDisplayListener("test"));
} }