mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-10-04 10:19:23 +02:00
added javadoc and improved root predicate for loop vertices. changed CIRCLE symbol name
GP-625 updated module IP for jungrapht 1.2 missing comma changed jungrapht version to 1.2 changed favored edge and comparator rename for updates to exp layouts updates for graph display api generalization renamed exp layout added placeholders for exp layouts removed problematic changes to layouts allow edge selection to be enabled. Begin to organize default graph api symbols in GraphDisplay updates full fix for GP-625
This commit is contained in:
parent
45927bb9c3
commit
76b66e2a53
12 changed files with 235 additions and 101 deletions
|
@ -31,6 +31,7 @@ import ghidra.program.model.pcode.*;
|
||||||
import ghidra.service.graph.*;
|
import ghidra.service.graph.*;
|
||||||
import ghidra.util.Msg;
|
import ghidra.util.Msg;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
import static ghidra.service.graph.GraphDisplay.*;
|
||||||
|
|
||||||
public class GraphAST extends GhidraScript {
|
public class GraphAST extends GhidraScript {
|
||||||
protected static final String COLOR_ATTRIBUTE = "Color";
|
protected static final String COLOR_ATTRIBUTE = "Color";
|
||||||
|
@ -66,11 +67,12 @@ public class GraphAST extends GhidraScript {
|
||||||
buildGraph();
|
buildGraph();
|
||||||
|
|
||||||
Map<String, String> properties = new HashMap<>();
|
Map<String, String> properties = new HashMap<>();
|
||||||
properties.put("selectedVertexColor", "0xFF1493");
|
properties.put(SELECTED_VERTEX_COLOR, "0xFF1493");
|
||||||
properties.put("selectedEdgeColor", "0xFF1493");
|
properties.put(SELECTED_EDGE_COLOR, "0xFF1493");
|
||||||
properties.put("initialLayoutAlgorithm", "Hierarchical MinCross Coffman Graham");
|
properties.put(INITIAL_LAYOUT_ALGORITHM, "Hierarchical MinCross Coffman Graham");
|
||||||
properties.put("displayVerticesAsIcons", "false");
|
properties.put(DISPLAY_VERTICES_AS_ICONS, "false");
|
||||||
properties.put("vertexLabelPosition", "S");
|
properties.put(VERTEX_LABEL_POSITION, "S");
|
||||||
|
properties.put(ENABLE_EDGE_SELECTION, "true");
|
||||||
GraphDisplay graphDisplay =
|
GraphDisplay graphDisplay =
|
||||||
graphDisplayBroker.getDefaultGraphDisplay(false, properties, monitor);
|
graphDisplayBroker.getDefaultGraphDisplay(false, properties, monitor);
|
||||||
// graphDisplay.defineVertexAttribute(CODE_ATTRIBUTE); //
|
// graphDisplay.defineVertexAttribute(CODE_ATTRIBUTE); //
|
||||||
|
|
|
@ -34,6 +34,8 @@ import ghidra.util.exception.GraphException;
|
||||||
import ghidra.util.task.Task;
|
import ghidra.util.task.Task;
|
||||||
import ghidra.util.task.TaskMonitor;
|
import ghidra.util.task.TaskMonitor;
|
||||||
|
|
||||||
|
import static ghidra.service.graph.GraphDisplay.*;
|
||||||
|
|
||||||
public class ASTGraphTask extends Task {
|
public class ASTGraphTask extends Task {
|
||||||
enum GraphType {
|
enum GraphType {
|
||||||
CONTROL_FLOW_GRAPH("AST Control Flow"), DATA_FLOW_GRAPH("AST Data Flow");
|
CONTROL_FLOW_GRAPH("AST Control Flow"), DATA_FLOW_GRAPH("AST Data Flow");
|
||||||
|
@ -104,9 +106,10 @@ public class ASTGraphTask extends Task {
|
||||||
createControlFlowGraph(graph, monitor);
|
createControlFlowGraph(graph, monitor);
|
||||||
}
|
}
|
||||||
Map<String, String> properties = new HashMap<>();
|
Map<String, String> properties = new HashMap<>();
|
||||||
properties.put("selectedVertexColor", "0xFF1493");
|
properties.put(SELECTED_VERTEX_COLOR, "0xFF1493");
|
||||||
properties.put("selectedEdgeColor", "0xFF1493");
|
properties.put(SELECTED_EDGE_COLOR, "0xFF1493");
|
||||||
properties.put("initialLayoutAlgorithm", "Hierarchical MinCross Coffman Graham");
|
properties.put(INITIAL_LAYOUT_ALGORITHM, "Hierarchical MinCross Coffman Graham");
|
||||||
|
properties.put(ENABLE_EDGE_SELECTION, "true");
|
||||||
GraphDisplay display = graphService.getDefaultGraphDisplay(!newGraph, properties, monitor);
|
GraphDisplay display = graphService.getDefaultGraphDisplay(!newGraph, properties, monitor);
|
||||||
ASTGraphDisplayListener displayListener =
|
ASTGraphDisplayListener displayListener =
|
||||||
new ASTGraphDisplayListener(tool, display, hfunction, graphType);
|
new ASTGraphDisplayListener(tool, display, hfunction, graphType);
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
EXCLUDE FROM GHIDRA JAR: true
|
EXCLUDE FROM GHIDRA JAR: true
|
||||||
|
|
||||||
MODULE FILE LICENSE: lib/jungrapht-visualization-1.1.jar BSD
|
MODULE FILE LICENSE: lib/jungrapht-visualization-1.2.jar BSD
|
||||||
MODULE FILE LICENSE: lib/jungrapht-layout-1.1.jar BSD
|
MODULE FILE LICENSE: lib/jungrapht-layout-1.2.jar BSD
|
||||||
MODULE FILE LICENSE: lib/jgrapht-core-1.5.0.jar LGPL 2.1
|
MODULE FILE LICENSE: lib/jgrapht-core-1.5.0.jar LGPL 2.1
|
||||||
MODULE FILE LICENSE: lib/jgrapht-io-1.5.0.jar LGPL 2.1
|
MODULE FILE LICENSE: lib/jgrapht-io-1.5.0.jar LGPL 2.1
|
||||||
MODULE FILE LICENSE: lib/jheaps-0.13.jar Apache License 2.0
|
MODULE FILE LICENSE: lib/jheaps-0.13.jar Apache License 2.0
|
||||||
|
|
|
@ -12,9 +12,9 @@ dependencies {
|
||||||
compile project(":Base")
|
compile project(":Base")
|
||||||
|
|
||||||
// jungrapht - exclude slf4j which produces a conflict with other uses with Ghidra
|
// jungrapht - exclude slf4j which produces a conflict with other uses with Ghidra
|
||||||
compile ("com.github.tomnelson:jungrapht-visualization:1.1") { exclude group: "org.slf4j", module: "slf4j-api" }
|
compile ("com.github.tomnelson:jungrapht-visualization:1.2") { exclude group: "org.slf4j", module: "slf4j-api" }
|
||||||
compile ("com.github.tomnelson:jungrapht-layout:1.1") { exclude group: "org.slf4j", module: "slf4j-api" }
|
compile ("com.github.tomnelson:jungrapht-layout:1.2") { exclude group: "org.slf4j", module: "slf4j-api" }
|
||||||
|
|
||||||
compile "org.jgrapht:jgrapht-core:1.5.0"
|
compile "org.jgrapht:jgrapht-core:1.5.0"
|
||||||
|
|
||||||
// not using jgrapht-io code that depends on antlr, so exclude antlr
|
// not using jgrapht-io code that depends on antlr, so exclude antlr
|
||||||
|
|
|
@ -103,28 +103,33 @@ public class DefaultGraphDisplay implements GraphDisplay {
|
||||||
|
|
||||||
private static final String ACTION_OWNER = "GraphServices";
|
private static final String ACTION_OWNER = "GraphServices";
|
||||||
|
|
||||||
/*
|
|
||||||
A handful of properties that can be set via the constructor
|
|
||||||
*/
|
|
||||||
private static final String SELECTED_VERTEX_COLOR = "selectedVertexColor";
|
|
||||||
private static final String SELECTED_EDGE_COLOR = "selectedEdgeColor";
|
|
||||||
private static final String INITIAL_LAYOUT_ALGORITHM = "initialLayoutAlgorithm";
|
|
||||||
private static final String DISPLAY_VERTICES_AS_ICONS = "displayVerticesAsIcons";
|
|
||||||
private static final String VERTEX_LABEL_POSITION = "vertexLabelPosition";
|
|
||||||
|
|
||||||
private static final int MAX_NODES = Integer.getInteger("maxNodes", 10000);
|
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);
|
||||||
|
|
||||||
private Logger log = Logger.getLogger(DefaultGraphDisplay.class.getName());
|
private Logger log = Logger.getLogger(DefaultGraphDisplay.class.getName());
|
||||||
|
|
||||||
private Map<String, String> displayProperties = new HashMap<>();
|
private Map<String, String> displayProperties;
|
||||||
private Set<DockingActionIf> addedActions = new LinkedHashSet<>();
|
private Set<DockingActionIf> addedActions = new LinkedHashSet<>();
|
||||||
private GraphDisplayListener listener = new DummyGraphDisplayListener();
|
private GraphDisplayListener listener = new DummyGraphDisplayListener();
|
||||||
private String title;
|
private String title;
|
||||||
|
|
||||||
private AttributedGraph graph;
|
private AttributedGraph graph;
|
||||||
|
|
||||||
|
private static String DEFAULT_EDGE_TYPE_PRIORITY_LIST =
|
||||||
|
"Fall-Through,"+
|
||||||
|
"Conditional-Return,"+
|
||||||
|
"Unconditional-Jump,"+
|
||||||
|
"Conditional-Jump,"+
|
||||||
|
"Unconditional-Call,"+
|
||||||
|
"Conditional-Call,"+
|
||||||
|
"Terminator,"+
|
||||||
|
"Computed,"+
|
||||||
|
"Indirection,"+
|
||||||
|
"Entry";
|
||||||
|
|
||||||
|
private static String DEFAULT_FAVORED_EDGES = "Fall-Through";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* a unique id for this {@link GraphDisplay}
|
* a unique id for this {@link GraphDisplay}
|
||||||
*/
|
*/
|
||||||
|
@ -219,7 +224,9 @@ public class DefaultGraphDisplay implements GraphDisplay {
|
||||||
viewer.getComponent().add(satelliteViewer.getComponent());
|
viewer.getComponent().add(satelliteViewer.getComponent());
|
||||||
}
|
}
|
||||||
layoutTransitionManager =
|
layoutTransitionManager =
|
||||||
new LayoutTransitionManager(viewer, this::isRoot);
|
new LayoutTransitionManager(viewer, this::isRoot,
|
||||||
|
getEdgeTypePriorityList(),
|
||||||
|
getFavoredEdgePredicate());
|
||||||
|
|
||||||
viewer.getComponent().addComponentListener(new ComponentAdapter() {
|
viewer.getComponent().addComponentListener(new ComponentAdapter() {
|
||||||
@Override
|
@Override
|
||||||
|
@ -252,6 +259,19 @@ public class DefaultGraphDisplay implements GraphDisplay {
|
||||||
return Colors.getHexColor(property);
|
return Colors.getHexColor(property);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private List<String> getEdgeTypePriorityList() {
|
||||||
|
return Arrays.asList(displayProperties
|
||||||
|
.getOrDefault(EDGE_TYPE_PRIORITY_LIST, DEFAULT_EDGE_TYPE_PRIORITY_LIST)
|
||||||
|
.split(","));
|
||||||
|
}
|
||||||
|
|
||||||
|
private Predicate<AttributedEdge> getFavoredEdgePredicate() {
|
||||||
|
String[] favoredEdges = displayProperties.getOrDefault(FAVORED_EDGES, DEFAULT_FAVORED_EDGES)
|
||||||
|
.split(",");
|
||||||
|
return attributedEdge -> Arrays.stream(favoredEdges)
|
||||||
|
.anyMatch(s -> s.equals(attributedEdge.getAttribute("EdgeType")));
|
||||||
|
}
|
||||||
|
|
||||||
JComponent getComponent() {
|
JComponent getComponent() {
|
||||||
JComponent component = viewer.getComponent();
|
JComponent component = viewer.getComponent();
|
||||||
component.setFocusable(true);
|
component.setFocusable(true);
|
||||||
|
@ -486,7 +506,7 @@ public class DefaultGraphDisplay implements GraphDisplay {
|
||||||
"Extends the current selection by including the target/source vertices " +
|
"Extends the current selection by including the target/source vertices " +
|
||||||
"of all edges whose source/target is selected")
|
"of all edges whose source/target is selected")
|
||||||
.keyBinding("ctrl C")
|
.keyBinding("ctrl C")
|
||||||
.enabledWhen(c -> !isAllSelected(getSourceVerticesFromSelected()) &&
|
.enabledWhen(c -> !isAllSelected(getSourceVerticesFromSelected()) ||
|
||||||
!isAllSelected(getTargetVerticesFromSelected()))
|
!isAllSelected(getTargetVerticesFromSelected()))
|
||||||
.onAction(c -> growSelection(getAllComponentVerticesFromSelected()))
|
.onAction(c -> growSelection(getAllComponentVerticesFromSelected()))
|
||||||
.buildAndInstallLocal(componentProvider);
|
.buildAndInstallLocal(componentProvider);
|
||||||
|
@ -610,6 +630,23 @@ public class DefaultGraphDisplay implements GraphDisplay {
|
||||||
|
|
||||||
private void growSelection(Set<AttributedVertex> vertices) {
|
private void growSelection(Set<AttributedVertex> vertices) {
|
||||||
viewer.getSelectedVertexState().select(vertices);
|
viewer.getSelectedVertexState().select(vertices);
|
||||||
|
selectEdgesConnecting(vertices);
|
||||||
|
}
|
||||||
|
|
||||||
|
// select all the edges that connect the supplied vertices
|
||||||
|
private void selectEdgesConnecting(Collection<AttributedVertex> vertices) {
|
||||||
|
viewer.getSelectedEdgeState().select(
|
||||||
|
graph.edgeSet()
|
||||||
|
.stream()
|
||||||
|
.filter(
|
||||||
|
e -> {
|
||||||
|
AttributedVertex source = graph.getEdgeSource(e);
|
||||||
|
AttributedVertex target = graph.getEdgeTarget(e);
|
||||||
|
return vertices.contains(source)
|
||||||
|
&& vertices.contains(target);
|
||||||
|
})
|
||||||
|
.collect(Collectors.toSet()));
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean isAllSelected(Set<AttributedVertex> vertices) {
|
private boolean isAllSelected(Set<AttributedVertex> vertices) {
|
||||||
|
@ -617,8 +654,8 @@ public class DefaultGraphDisplay implements GraphDisplay {
|
||||||
}
|
}
|
||||||
|
|
||||||
private Set<AttributedVertex> getSourceVerticesFromSelected() {
|
private Set<AttributedVertex> getSourceVerticesFromSelected() {
|
||||||
Set<AttributedVertex> sources = new HashSet<>();
|
|
||||||
Set<AttributedVertex> selectedVertices = getSelectedVertices();
|
Set<AttributedVertex> selectedVertices = getSelectedVertices();
|
||||||
|
Set<AttributedVertex> sources = new HashSet<>(selectedVertices);
|
||||||
for (AttributedVertex v : selectedVertices) {
|
for (AttributedVertex v : selectedVertices) {
|
||||||
Set<AttributedEdge> edges = graph.incomingEdgesOf(v);
|
Set<AttributedEdge> edges = graph.incomingEdgesOf(v);
|
||||||
edges.forEach(e -> sources.add(graph.getEdgeSource(e)));
|
edges.forEach(e -> sources.add(graph.getEdgeSource(e)));
|
||||||
|
@ -635,8 +672,8 @@ public class DefaultGraphDisplay implements GraphDisplay {
|
||||||
}
|
}
|
||||||
|
|
||||||
private Set<AttributedVertex> getTargetVerticesFromSelected() {
|
private Set<AttributedVertex> getTargetVerticesFromSelected() {
|
||||||
Set<AttributedVertex> targets = new HashSet<>();
|
|
||||||
Set<AttributedVertex> selectedVertices = getSelectedVertices();
|
Set<AttributedVertex> selectedVertices = getSelectedVertices();
|
||||||
|
Set<AttributedVertex> targets = new HashSet<>(selectedVertices);
|
||||||
for (AttributedVertex v : selectedVertices) {
|
for (AttributedVertex v : selectedVertices) {
|
||||||
Set<AttributedEdge> edges = graph.outgoingEdgesOf(v);
|
Set<AttributedEdge> edges = graph.outgoingEdgesOf(v);
|
||||||
edges.forEach(e -> targets.add(graph.getEdgeTarget(e)));
|
edges.forEach(e -> targets.add(graph.getEdgeTarget(e)));
|
||||||
|
@ -674,9 +711,20 @@ public class DefaultGraphDisplay implements GraphDisplay {
|
||||||
return upstream;
|
return upstream;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gather all source and target vertices until there are no more available.
|
||||||
|
* @return all the vertices in the component(s) of the selected vertices
|
||||||
|
*/
|
||||||
public Set<AttributedVertex> getAllComponentVerticesFromSelected() {
|
public Set<AttributedVertex> getAllComponentVerticesFromSelected() {
|
||||||
Set<AttributedVertex> componentVertices = getAllDownstreamVerticesFromSelected();
|
Set<AttributedVertex> componentVertices = new HashSet<>(viewer.getSelectedVertices());
|
||||||
componentVertices.addAll(getAllUpstreamVerticesFromSelected());
|
Set<AttributedVertex> downstream = getAllDownstreamVerticesFromSelected();
|
||||||
|
Set<AttributedVertex> upstream = getAllUpstreamVerticesFromSelected();
|
||||||
|
while (!downstream.isEmpty() || !upstream.isEmpty()) {
|
||||||
|
componentVertices.addAll(downstream);
|
||||||
|
componentVertices.addAll(upstream);
|
||||||
|
downstream = getAllDownstreamVerticesFromSelected();
|
||||||
|
upstream = getAllUpstreamVerticesFromSelected();
|
||||||
|
}
|
||||||
return componentVertices;
|
return componentVertices;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -974,13 +1022,14 @@ public class DefaultGraphDisplay implements GraphDisplay {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Determines if a vertex is a root. For our purpose, a root either has no incoming edges
|
* Determines if a vertex is a root. For our purpose, a root either has no incoming edges
|
||||||
* or has at least one outgoing "favored" edge and no incoming "favored" edge
|
* or if all edges of a vertex are 'loop' edges
|
||||||
* @param vertex the vertex to test if it is a root
|
* @param vertex the vertex to test if it is a root
|
||||||
* @return true if the vertex is a root
|
* @return true if the vertex is a root
|
||||||
*/
|
*/
|
||||||
private boolean isRoot(AttributedVertex vertex) {
|
private boolean isRoot(AttributedVertex vertex) {
|
||||||
Set<AttributedEdge> incomingEdgesOf = graph.incomingEdgesOf(vertex);
|
Set<AttributedEdge> incomingEdgesOf = graph.incomingEdgesOf(vertex);
|
||||||
return incomingEdgesOf.isEmpty();
|
return incomingEdgesOf.isEmpty() ||
|
||||||
|
graph.incomingEdgesOf(vertex).equals(graph.outgoingEdgesOf(vertex));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1249,12 +1298,6 @@ public class DefaultGraphDisplay implements GraphDisplay {
|
||||||
|
|
||||||
setVertexPreferences(vv);
|
setVertexPreferences(vv);
|
||||||
|
|
||||||
// the selectedEdgeState will be controlled by the vertices that are selected.
|
|
||||||
// if both endpoints of an edge are selected, select that edge.
|
|
||||||
vv.setSelectedEdgeState(
|
|
||||||
new VertexEndpointsSelectedEdgeSelectedState<>(vv.getVisualizationModel()::getGraph,
|
|
||||||
vv.getSelectedVertexState()));
|
|
||||||
|
|
||||||
// selected edges will be drawn with a wider stroke
|
// selected edges will be drawn with a wider stroke
|
||||||
renderContext.setEdgeStrokeFunction(
|
renderContext.setEdgeStrokeFunction(
|
||||||
e -> isSelected(e) ? new BasicStroke(20.f)
|
e -> isSelected(e) ? new BasicStroke(20.f)
|
||||||
|
@ -1278,7 +1321,6 @@ public class DefaultGraphDisplay implements GraphDisplay {
|
||||||
|
|
||||||
// cause the lightweight (optimized) renderer to use the vertex shapes instead
|
// cause the lightweight (optimized) renderer to use the vertex shapes instead
|
||||||
// of using default shapes.
|
// of using default shapes.
|
||||||
|
|
||||||
if (vertexRenderer instanceof LightweightVertexRenderer) {
|
if (vertexRenderer instanceof LightweightVertexRenderer) {
|
||||||
Function<AttributedVertex, Shape> vertexShapeFunction =
|
Function<AttributedVertex, Shape> vertexShapeFunction =
|
||||||
renderContext.getVertexShapeFunction();
|
renderContext.getVertexShapeFunction();
|
||||||
|
@ -1301,7 +1343,9 @@ public class DefaultGraphDisplay implements GraphDisplay {
|
||||||
vv.getComponent().removeMouseListener(mouseListener);
|
vv.getComponent().removeMouseListener(mouseListener);
|
||||||
}
|
}
|
||||||
|
|
||||||
graphMouse = new JgtGraphMouse(this);
|
graphMouse = new JgtGraphMouse(this,
|
||||||
|
Boolean.parseBoolean(displayProperties.getOrDefault(ENABLE_EDGE_SELECTION,
|
||||||
|
"false")));
|
||||||
vv.setGraphMouse(graphMouse);
|
vv.setGraphMouse(graphMouse);
|
||||||
|
|
||||||
return vv;
|
return vv;
|
||||||
|
|
|
@ -15,7 +15,9 @@
|
||||||
*/
|
*/
|
||||||
package ghidra.graph.visualization;
|
package ghidra.graph.visualization;
|
||||||
|
|
||||||
|
import java.util.Comparator;
|
||||||
import java.util.function.Function;
|
import java.util.function.Function;
|
||||||
|
import java.util.function.Predicate;
|
||||||
|
|
||||||
import org.jungrapht.visualization.layout.algorithms.*;
|
import org.jungrapht.visualization.layout.algorithms.*;
|
||||||
import org.jungrapht.visualization.layout.algorithms.repulsion.BarnesHutFRRepulsion;
|
import org.jungrapht.visualization.layout.algorithms.repulsion.BarnesHutFRRepulsion;
|
||||||
|
@ -36,22 +38,38 @@ class LayoutFunction
|
||||||
|
|
||||||
static final String KAMADA_KAWAI = "Force Balanced";
|
static final String KAMADA_KAWAI = "Force Balanced";
|
||||||
static final String FRUCTERMAN_REINGOLD = "Force Directed";
|
static final String FRUCTERMAN_REINGOLD = "Force Directed";
|
||||||
static final String CIRCLE_MINCROSS = "Circle";
|
static final String CIRCLE = "Circle";
|
||||||
static final String TIDIER_TREE = "Compact Hierarchical";
|
static final String TIDIER_TREE = "Compact Hierarchical";
|
||||||
static final String TIDIER_RADIAL_TREE = "Compact Radial";
|
static final String TIDIER_RADIAL_TREE = "Compact Radial";
|
||||||
static final String MIN_CROSS_TOP_DOWN = "Hierarchical MinCross Top Down";
|
static final String MIN_CROSS_TOP_DOWN = "Hierarchical MinCross Top Down";
|
||||||
static final String MIN_CROSS_LONGEST_PATH = "Hierarchical MinCross Longest Path";
|
static final String MIN_CROSS_LONGEST_PATH = "Hierarchical MinCross Longest Path";
|
||||||
static final String MIN_CROSS_NETWORK_SIMPLEX = "Hierarchical MinCross Network Simplex";
|
static final String MIN_CROSS_NETWORK_SIMPLEX = "Hierarchical MinCross Network Simplex";
|
||||||
static final String MIN_CROSS_COFFMAN_GRAHAM = "Hierarchical MinCross Coffman Graham";
|
static final String MIN_CROSS_COFFMAN_GRAHAM = "Hierarchical MinCross Coffman Graham";
|
||||||
|
static final String EXP_MIN_CROSS_TOP_DOWN = "Experimental Hierarchical MinCross Top Down";
|
||||||
|
static final String EXP_MIN_CROSS_LONGEST_PATH = "Experimental Hierarchical MinCross Longest Path";
|
||||||
|
static final String EXP_MIN_CROSS_NETWORK_SIMPLEX = "Experimental Hierarchical MinCross Network Simplex";
|
||||||
|
static final String EXP_MIN_CROSS_COFFMAN_GRAHAM = "Experimental Hierarchical MinCross Coffman Graham";
|
||||||
static final String TREE = "Hierarchical";
|
static final String TREE = "Hierarchical";
|
||||||
static final String RADIAL = "Radial";
|
static final String RADIAL = "Radial";
|
||||||
static final String BALLOON = "Balloon";
|
static final String BALLOON = "Balloon";
|
||||||
static final String GEM = "Gem (Graph Embedder)";
|
static final String GEM = "Gem (Graph Embedder)";
|
||||||
|
|
||||||
|
Predicate<AttributedEdge> favoredEdgePredicate;
|
||||||
|
Comparator<AttributedEdge> edgeTypeComparator;
|
||||||
|
|
||||||
|
LayoutFunction(Comparator<AttributedEdge> edgeTypeComparator, Predicate<AttributedEdge> favoredEdgePredicate) {
|
||||||
|
this.edgeTypeComparator = edgeTypeComparator;
|
||||||
|
this.favoredEdgePredicate = favoredEdgePredicate;
|
||||||
|
}
|
||||||
|
|
||||||
public String[] getNames() {
|
public String[] getNames() {
|
||||||
return new String[] { TIDIER_TREE, TREE,
|
return new String[] { TIDIER_TREE, TREE,
|
||||||
TIDIER_RADIAL_TREE, MIN_CROSS_TOP_DOWN, MIN_CROSS_LONGEST_PATH,
|
TIDIER_RADIAL_TREE, MIN_CROSS_TOP_DOWN, MIN_CROSS_LONGEST_PATH,
|
||||||
MIN_CROSS_NETWORK_SIMPLEX, MIN_CROSS_COFFMAN_GRAHAM, CIRCLE_MINCROSS,
|
MIN_CROSS_NETWORK_SIMPLEX, MIN_CROSS_COFFMAN_GRAHAM, CIRCLE,
|
||||||
|
EXP_MIN_CROSS_TOP_DOWN,
|
||||||
|
EXP_MIN_CROSS_LONGEST_PATH,
|
||||||
|
EXP_MIN_CROSS_NETWORK_SIMPLEX,
|
||||||
|
EXP_MIN_CROSS_COFFMAN_GRAHAM,
|
||||||
KAMADA_KAWAI, FRUCTERMAN_REINGOLD, RADIAL, BALLOON, GEM
|
KAMADA_KAWAI, FRUCTERMAN_REINGOLD, RADIAL, BALLOON, GEM
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -67,27 +85,56 @@ class LayoutFunction
|
||||||
case FRUCTERMAN_REINGOLD:
|
case FRUCTERMAN_REINGOLD:
|
||||||
return FRLayoutAlgorithm.<AttributedVertex> builder()
|
return FRLayoutAlgorithm.<AttributedVertex> builder()
|
||||||
.repulsionContractBuilder(BarnesHutFRRepulsion.builder());
|
.repulsionContractBuilder(BarnesHutFRRepulsion.builder());
|
||||||
case CIRCLE_MINCROSS:
|
case CIRCLE:
|
||||||
return CircleLayoutAlgorithm.<AttributedVertex> builder()
|
return CircleLayoutAlgorithm.<AttributedVertex> builder()
|
||||||
.reduceEdgeCrossing(true);
|
.reduceEdgeCrossing(false);
|
||||||
case TIDIER_RADIAL_TREE:
|
case TIDIER_RADIAL_TREE:
|
||||||
return TidierRadialTreeLayoutAlgorithm
|
return TidierRadialTreeLayoutAlgorithm
|
||||||
.<AttributedVertex, AttributedEdge> edgeAwareBuilder();
|
.<AttributedVertex, AttributedEdge> edgeAwareBuilder()
|
||||||
|
.edgeComparator(edgeTypeComparator);
|
||||||
case MIN_CROSS_TOP_DOWN:
|
case MIN_CROSS_TOP_DOWN:
|
||||||
return EiglspergerLayoutAlgorithm
|
return EiglspergerLayoutAlgorithm
|
||||||
.<AttributedVertex, AttributedEdge> edgeAwareBuilder()
|
.<AttributedVertex, AttributedEdge> edgeAwareBuilder()
|
||||||
|
.edgeComparator(edgeTypeComparator)
|
||||||
.layering(Layering.TOP_DOWN);
|
.layering(Layering.TOP_DOWN);
|
||||||
case MIN_CROSS_LONGEST_PATH:
|
case MIN_CROSS_LONGEST_PATH:
|
||||||
return EiglspergerLayoutAlgorithm
|
return EiglspergerLayoutAlgorithm
|
||||||
.<AttributedVertex, AttributedEdge> edgeAwareBuilder()
|
.<AttributedVertex, AttributedEdge> edgeAwareBuilder()
|
||||||
|
.edgeComparator(edgeTypeComparator)
|
||||||
.layering(Layering.LONGEST_PATH);
|
.layering(Layering.LONGEST_PATH);
|
||||||
case MIN_CROSS_NETWORK_SIMPLEX:
|
case MIN_CROSS_NETWORK_SIMPLEX:
|
||||||
return EiglspergerLayoutAlgorithm
|
return EiglspergerLayoutAlgorithm
|
||||||
.<AttributedVertex, AttributedEdge> edgeAwareBuilder()
|
.<AttributedVertex, AttributedEdge> edgeAwareBuilder()
|
||||||
|
.edgeComparator(edgeTypeComparator)
|
||||||
.layering(Layering.NETWORK_SIMPLEX);
|
.layering(Layering.NETWORK_SIMPLEX);
|
||||||
case MIN_CROSS_COFFMAN_GRAHAM:
|
case MIN_CROSS_COFFMAN_GRAHAM:
|
||||||
return EiglspergerLayoutAlgorithm
|
return EiglspergerLayoutAlgorithm
|
||||||
.<AttributedVertex, AttributedEdge> edgeAwareBuilder()
|
.<AttributedVertex, AttributedEdge> edgeAwareBuilder()
|
||||||
|
.edgeComparator(edgeTypeComparator)
|
||||||
|
.layering(Layering.COFFMAN_GRAHAM);
|
||||||
|
case EXP_MIN_CROSS_TOP_DOWN:
|
||||||
|
return EiglspergerLayoutAlgorithm
|
||||||
|
.<AttributedVertex, AttributedEdge> edgeAwareBuilder()
|
||||||
|
.edgeComparator(edgeTypeComparator)
|
||||||
|
.favoredEdgePredicate(favoredEdgePredicate)
|
||||||
|
.layering(Layering.TOP_DOWN);
|
||||||
|
case EXP_MIN_CROSS_LONGEST_PATH:
|
||||||
|
return EiglspergerLayoutAlgorithm
|
||||||
|
.<AttributedVertex, AttributedEdge> edgeAwareBuilder()
|
||||||
|
.edgeComparator(edgeTypeComparator)
|
||||||
|
.favoredEdgePredicate(favoredEdgePredicate)
|
||||||
|
.layering(Layering.LONGEST_PATH);
|
||||||
|
case EXP_MIN_CROSS_NETWORK_SIMPLEX:
|
||||||
|
return EiglspergerLayoutAlgorithm
|
||||||
|
.<AttributedVertex, AttributedEdge> edgeAwareBuilder()
|
||||||
|
.edgeComparator(edgeTypeComparator)
|
||||||
|
.favoredEdgePredicate(favoredEdgePredicate)
|
||||||
|
.layering(Layering.NETWORK_SIMPLEX);
|
||||||
|
case EXP_MIN_CROSS_COFFMAN_GRAHAM:
|
||||||
|
return EiglspergerLayoutAlgorithm
|
||||||
|
.<AttributedVertex, AttributedEdge> edgeAwareBuilder()
|
||||||
|
.edgeComparator(edgeTypeComparator)
|
||||||
|
.favoredEdgePredicate(favoredEdgePredicate)
|
||||||
.layering(Layering.COFFMAN_GRAHAM);
|
.layering(Layering.COFFMAN_GRAHAM);
|
||||||
case RADIAL:
|
case RADIAL:
|
||||||
return RadialTreeLayoutAlgorithm
|
return RadialTreeLayoutAlgorithm
|
||||||
|
@ -103,7 +150,9 @@ class LayoutFunction
|
||||||
case TIDIER_TREE:
|
case TIDIER_TREE:
|
||||||
default:
|
default:
|
||||||
return TidierTreeLayoutAlgorithm
|
return TidierTreeLayoutAlgorithm
|
||||||
.<AttributedVertex, AttributedEdge> edgeAwareBuilder();
|
.<AttributedVertex, AttributedEdge> edgeAwareBuilder()
|
||||||
|
.edgeComparator(edgeTypeComparator);
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -38,7 +38,7 @@ import ghidra.service.graph.AttributedVertex;
|
||||||
*/
|
*/
|
||||||
class LayoutTransitionManager {
|
class LayoutTransitionManager {
|
||||||
|
|
||||||
LayoutFunction layoutFunction = new LayoutFunction();
|
LayoutFunction layoutFunction;
|
||||||
/**
|
/**
|
||||||
* the {@link VisualizationServer} used to display graphs using the requested {@link LayoutAlgorithm}
|
* the {@link VisualizationServer} used to display graphs using the requested {@link LayoutAlgorithm}
|
||||||
*/
|
*/
|
||||||
|
@ -49,24 +49,6 @@ class LayoutTransitionManager {
|
||||||
*/
|
*/
|
||||||
Predicate<AttributedVertex> rootPredicate;
|
Predicate<AttributedVertex> rootPredicate;
|
||||||
|
|
||||||
public static final List<String> EDGE_PRIORITY_LIST =
|
|
||||||
List.of(
|
|
||||||
"Fall-Through",
|
|
||||||
"Conditional-Return",
|
|
||||||
"Unconditional-Jump",
|
|
||||||
"Conditional-Jump",
|
|
||||||
"Unconditional-Call",
|
|
||||||
"Conditional-Call",
|
|
||||||
"Terminator",
|
|
||||||
"Computed",
|
|
||||||
"Indirection",
|
|
||||||
"Entry");
|
|
||||||
/**
|
|
||||||
* a {@link Comparator} to sort edges during layout graph traversal
|
|
||||||
* The default uses the {@code EDGE_PRIORTITY_LIST }
|
|
||||||
*/
|
|
||||||
Comparator<AttributedEdge> edgeComparator = new EdgeComparator(EDGE_PRIORITY_LIST);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* a {@link Function} to provide {@link Rectangle} (and thus bounds} for vertices
|
* a {@link Function} to provide {@link Rectangle} (and thus bounds} for vertices
|
||||||
*/
|
*/
|
||||||
|
@ -81,47 +63,54 @@ class LayoutTransitionManager {
|
||||||
|
|
||||||
LayoutPaintable.RadialRings<AttributedVertex> radialLayoutRings;
|
LayoutPaintable.RadialRings<AttributedVertex> radialLayoutRings;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create an instance with passed parameters
|
* Create an instance with passed parameters
|
||||||
* @param visualizationServer displays the graph
|
* @param visualizationServer displays the graph
|
||||||
* @param rootPredicate selects root vertices
|
* @param rootPredicate selects root vertices
|
||||||
|
* @param edgeTypePriorityList a {@code List} of EdgeType names in priority order
|
||||||
|
* @param favoredEdgePredicate q {@code Predicate} that will cause certain EdgeTypes to be favored during layout
|
||||||
*/
|
*/
|
||||||
public LayoutTransitionManager(
|
public LayoutTransitionManager(
|
||||||
VisualizationServer<AttributedVertex, AttributedEdge> visualizationServer,
|
VisualizationServer<AttributedVertex, AttributedEdge> visualizationServer,
|
||||||
Predicate<AttributedVertex> rootPredicate) {
|
Predicate<AttributedVertex> rootPredicate,
|
||||||
|
List<String> edgeTypePriorityList,
|
||||||
|
Predicate<AttributedEdge> favoredEdgePredicate) {
|
||||||
this.visualizationServer = visualizationServer;
|
this.visualizationServer = visualizationServer;
|
||||||
this.rootPredicate = rootPredicate;
|
this.rootPredicate = rootPredicate;
|
||||||
|
|
||||||
this.renderContext = visualizationServer.getRenderContext();
|
this.renderContext = visualizationServer.getRenderContext();
|
||||||
this.vertexBoundsFunction = visualizationServer.getRenderContext().getVertexBoundsFunction();
|
this.vertexBoundsFunction = visualizationServer.getRenderContext().getVertexBoundsFunction();
|
||||||
}
|
this.layoutFunction = new LayoutFunction(new EdgeComparator(edgeTypePriorityList),
|
||||||
|
favoredEdgePredicate);
|
||||||
public void setEdgeComparator(Comparator<AttributedEdge> edgeComparator) {
|
|
||||||
this.edgeComparator = edgeComparator;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* set the layout in order to configure the requested {@link LayoutAlgorithm}
|
* set the layout in order to configure the requested {@link LayoutAlgorithm}
|
||||||
* @param layoutName the name of the layout algorithm to use
|
* @param layoutName the name of the layout algorithm to use
|
||||||
*/
|
*/
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
public void setLayout(String layoutName) {
|
public void setLayout(String layoutName) {
|
||||||
LayoutAlgorithm.Builder<AttributedVertex, ?, ?> builder = layoutFunction.apply(layoutName);
|
LayoutAlgorithm.Builder<AttributedVertex, ?, ?> builder = layoutFunction.apply(layoutName);
|
||||||
LayoutAlgorithm<AttributedVertex> layoutAlgorithm = builder.build();
|
LayoutAlgorithm<AttributedVertex> layoutAlgorithm = builder.build();
|
||||||
|
// layout algorithm considers the size of vertices
|
||||||
if (layoutAlgorithm instanceof VertexBoundsFunctionConsumer) {
|
if (layoutAlgorithm instanceof VertexBoundsFunctionConsumer) {
|
||||||
((VertexBoundsFunctionConsumer<AttributedVertex>) layoutAlgorithm)
|
((VertexBoundsFunctionConsumer<AttributedVertex>) layoutAlgorithm)
|
||||||
.setVertexBoundsFunction(vertexBoundsFunction);
|
.setVertexBoundsFunction(vertexBoundsFunction);
|
||||||
}
|
}
|
||||||
|
// mincross layouts are 'layered'. put some bounds on the number of
|
||||||
|
// iterations of the level cross function based on the size of the graph
|
||||||
|
// very large graphs do not improve enough to out-weigh the cost of
|
||||||
|
// repeated iterations
|
||||||
if (layoutAlgorithm instanceof Layered) {
|
if (layoutAlgorithm instanceof Layered) {
|
||||||
((Layered<AttributedVertex, AttributedEdge>) layoutAlgorithm)
|
((Layered<AttributedVertex, AttributedEdge>) layoutAlgorithm)
|
||||||
.setMaxLevelCrossFunction(g ->
|
.setMaxLevelCrossFunction(g ->
|
||||||
Math.max(1, Math.min(10, 500 / g.vertexSet().size())));
|
Math.max(1, Math.min(10, 500 / g.vertexSet().size())));
|
||||||
}
|
}
|
||||||
|
// tree layouts need a way to determine which vertices are roots
|
||||||
|
// especially when the graph is not a DAG
|
||||||
if (layoutAlgorithm instanceof TreeLayout) {
|
if (layoutAlgorithm instanceof TreeLayout) {
|
||||||
((TreeLayout<AttributedVertex>) layoutAlgorithm).setRootPredicate(rootPredicate);
|
((TreeLayout<AttributedVertex>) layoutAlgorithm).setRootPredicate(rootPredicate);
|
||||||
}
|
}
|
||||||
// remove any previously added layout paintables
|
// remove any previously added layout paintables
|
||||||
|
// and apply paintables to these 2 algorithms
|
||||||
removePaintable(radialLayoutRings);
|
removePaintable(radialLayoutRings);
|
||||||
removePaintable(balloonLayoutRings);
|
removePaintable(balloonLayoutRings);
|
||||||
if (layoutAlgorithm instanceof BalloonLayoutAlgorithm) {
|
if (layoutAlgorithm instanceof BalloonLayoutAlgorithm) {
|
||||||
|
@ -138,9 +127,7 @@ class LayoutTransitionManager {
|
||||||
visualizationServer.addPreRenderPaintable(radialLayoutRings);
|
visualizationServer.addPreRenderPaintable(radialLayoutRings);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (layoutAlgorithm instanceof EdgeSorting) {
|
// apply the layout algorithm
|
||||||
((EdgeSorting<AttributedEdge>) layoutAlgorithm).setEdgeComparator(edgeComparator);
|
|
||||||
}
|
|
||||||
LayoutAlgorithmTransition.apply(visualizationServer,
|
LayoutAlgorithmTransition.apply(visualizationServer,
|
||||||
layoutAlgorithm);
|
layoutAlgorithm);
|
||||||
}
|
}
|
||||||
|
@ -151,7 +138,10 @@ class LayoutTransitionManager {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
/**
|
||||||
|
* Supplies the {@code LayoutAlgorithm} to be used for the initial @{code Graph} visualization
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
public LayoutAlgorithm<AttributedVertex> getInitialLayoutAlgorithm() {
|
public LayoutAlgorithm<AttributedVertex> getInitialLayoutAlgorithm() {
|
||||||
LayoutAlgorithm<AttributedVertex> initialLayoutAlgorithm =
|
LayoutAlgorithm<AttributedVertex> initialLayoutAlgorithm =
|
||||||
layoutFunction.apply(TIDIER_TREE).build();
|
layoutFunction.apply(TIDIER_TREE).build();
|
||||||
|
@ -159,12 +149,6 @@ class LayoutTransitionManager {
|
||||||
if (initialLayoutAlgorithm instanceof TreeLayout) {
|
if (initialLayoutAlgorithm instanceof TreeLayout) {
|
||||||
((TreeLayout<AttributedVertex>) initialLayoutAlgorithm)
|
((TreeLayout<AttributedVertex>) initialLayoutAlgorithm)
|
||||||
.setRootPredicate(rootPredicate);
|
.setRootPredicate(rootPredicate);
|
||||||
((TreeLayout<AttributedVertex>) initialLayoutAlgorithm)
|
|
||||||
.setVertexBoundsFunction(vertexBoundsFunction);
|
|
||||||
}
|
|
||||||
if (initialLayoutAlgorithm instanceof EdgeSorting) {
|
|
||||||
((EdgeSorting<AttributedEdge>) initialLayoutAlgorithm)
|
|
||||||
.setEdgeComparator(edgeComparator);
|
|
||||||
}
|
}
|
||||||
if (initialLayoutAlgorithm instanceof VertexBoundsFunctionConsumer) {
|
if (initialLayoutAlgorithm instanceof VertexBoundsFunctionConsumer) {
|
||||||
((VertexBoundsFunctionConsumer<AttributedVertex>) initialLayoutAlgorithm)
|
((VertexBoundsFunctionConsumer<AttributedVertex>) initialLayoutAlgorithm)
|
||||||
|
@ -173,6 +157,10 @@ class LayoutTransitionManager {
|
||||||
return initialLayoutAlgorithm;
|
return initialLayoutAlgorithm;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Supplies a {@code String[]} array of the supported layout names
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
public String[] getLayoutNames() {
|
public String[] getLayoutNames() {
|
||||||
return layoutFunction.getNames();
|
return layoutFunction.getNames();
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,12 +29,14 @@ import ghidra.service.graph.AttributedVertex;
|
||||||
public class JgtGraphMouse extends DefaultGraphMouse<AttributedVertex, AttributedEdge> {
|
public class JgtGraphMouse extends DefaultGraphMouse<AttributedVertex, AttributedEdge> {
|
||||||
|
|
||||||
private DefaultGraphDisplay graphDisplay;
|
private DefaultGraphDisplay graphDisplay;
|
||||||
|
private boolean allowEdgeSelection;
|
||||||
|
|
||||||
// TODO we should not need the graph display for any mouse plugins, but the API is net yet
|
// TODO we should not need the graph display for any mouse plugins, but the API is net yet
|
||||||
// robust enough to communicate fully without it
|
// robust enough to communicate fully without it
|
||||||
public JgtGraphMouse(DefaultGraphDisplay graphDisplay) {
|
public JgtGraphMouse(DefaultGraphDisplay graphDisplay, boolean allowEdgeSelection) {
|
||||||
super(DefaultGraphMouse.builder());
|
super(DefaultGraphMouse.builder());
|
||||||
this.graphDisplay = graphDisplay;
|
this.graphDisplay = graphDisplay;
|
||||||
|
this.allowEdgeSelection = allowEdgeSelection;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -54,13 +56,13 @@ public class JgtGraphMouse extends DefaultGraphMouse<AttributedVertex, Attribute
|
||||||
// JUNGRAPHT CHANGE 1,2
|
// JUNGRAPHT CHANGE 1,2
|
||||||
//
|
//
|
||||||
// Note: this code can go away when we can turn off the picking square
|
// Note: this code can go away when we can turn off the picking square
|
||||||
add(new JgtSelectingGraphMousePlugin());
|
add(allowEdgeSelection ? new SelectingGraphMousePlugin() : new VertexSelectingGraphMousePlugin<>());
|
||||||
// add(new SelectingGraphMousePlugin<>());
|
// add(new SelectingGraphMousePlugin<>());
|
||||||
|
|
||||||
add(new RegionSelectingGraphMousePlugin<>());
|
add(new RegionSelectingGraphMousePlugin<>());
|
||||||
|
|
||||||
// the grab/pan feature
|
// the grab/pan feature
|
||||||
add(new TranslatingGraphMousePlugin(InputEvent.BUTTON1_DOWN_MASK));
|
add(TranslatingGraphMousePlugin.builder().translatingMask(InputEvent.BUTTON1_DOWN_MASK).build());
|
||||||
|
|
||||||
// scaling
|
// scaling
|
||||||
add(new ScalingGraphMousePlugin());
|
add(new ScalingGraphMousePlugin());
|
||||||
|
|
|
@ -39,19 +39,21 @@ public class JgtSatelliteGraphMouse
|
||||||
//
|
//
|
||||||
// JUNGRAPHT CHANGE 3
|
// JUNGRAPHT CHANGE 3
|
||||||
//
|
//
|
||||||
|
// disable single selection in satellite view by setting masks to 0
|
||||||
SelectingGraphMousePlugin<AttributedVertex, AttributedEdge> mySelectingPlugin =
|
SelectingGraphMousePlugin<AttributedVertex, AttributedEdge> mySelectingPlugin =
|
||||||
new JgtSelectingGraphMousePlugin(singleSelectionMask, addSingleSelectionMask);
|
new JgtSelectingGraphMousePlugin(0, 0);
|
||||||
mySelectingPlugin.setLocked(true);
|
mySelectingPlugin.setLocked(true);
|
||||||
selectingPlugin = mySelectingPlugin;
|
selectingPlugin = mySelectingPlugin;
|
||||||
|
|
||||||
regionSelectingPlugin =
|
regionSelectingPlugin =
|
||||||
RegionSelectingGraphMousePlugin.builder()
|
RegionSelectingGraphMousePlugin.builder()
|
||||||
.regionSelectionMask(regionSelectionMask)
|
.regionSelectionMask(regionSelectionMask)
|
||||||
.addRegionSelectionMask(addRegionSelectionMask)
|
.toggleRegionSelectionMask(toggleRegionSelectionMask)
|
||||||
.regionSelectionCompleteMask(regionSelectionCompleteMask)
|
.regionSelectionCompleteMask(regionSelectionCompleteMask)
|
||||||
.addRegionSelectionCompleteMask(addRegionSelectionCompleteMask)
|
.toggleRegionSelectionCompleteMask(toggleRegionSelectionCompleteMask)
|
||||||
.build();
|
.build();
|
||||||
translatingPlugin = new SatelliteTranslatingGraphMousePlugin(translatingMask);
|
translatingPlugin = SatelliteTranslatingGraphMousePlugin.builder()
|
||||||
|
.translatingMask(translatingMask).build();
|
||||||
add(selectingPlugin);
|
add(selectingPlugin);
|
||||||
add(regionSelectingPlugin);
|
add(regionSelectingPlugin);
|
||||||
add(translatingPlugin);
|
add(translatingPlugin);
|
||||||
|
|
|
@ -54,8 +54,10 @@ public class JgtSelectingGraphMousePlugin
|
||||||
this.pickFootprintPaintable = dummyPickFootprintPaintable;
|
this.pickFootprintPaintable = dummyPickFootprintPaintable;
|
||||||
}
|
}
|
||||||
|
|
||||||
public JgtSelectingGraphMousePlugin(int singleSelectionMask, int addSingleSelectionMask) {
|
public JgtSelectingGraphMousePlugin(int singleSelectionMask, int toggleSingleSelectionMask) {
|
||||||
super(singleSelectionMask, addSingleSelectionMask);
|
super(SelectingGraphMousePlugin.<AttributedVertex, AttributedEdge>builder()
|
||||||
|
.singleSelectionMask(singleSelectionMask)
|
||||||
|
.toggleSingleSelectionMask(toggleSingleSelectionMask));
|
||||||
|
|
||||||
//
|
//
|
||||||
// JUNGRAPHT CHANGE 1
|
// JUNGRAPHT CHANGE 1
|
||||||
|
@ -89,7 +91,6 @@ public class JgtSelectingGraphMousePlugin
|
||||||
selectedVertexState.clear();
|
selectedVertexState.clear();
|
||||||
}
|
}
|
||||||
selectedVertexState.select(vertex);
|
selectedVertexState.select(vertex);
|
||||||
deselectedVertex = null;
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// If this vertex is still around in mouseReleased, it will be deselected
|
// If this vertex is still around in mouseReleased, it will be deselected
|
||||||
|
@ -99,9 +100,6 @@ public class JgtSelectingGraphMousePlugin
|
||||||
//
|
//
|
||||||
// JUNGRAPHT CHANGE 2 HERE
|
// JUNGRAPHT CHANGE 2 HERE
|
||||||
//
|
//
|
||||||
if (addToSelection) {
|
|
||||||
deselectedVertex = vertex;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
e.consume();
|
e.consume();
|
||||||
return true;
|
return true;
|
||||||
|
|
|
@ -13,8 +13,8 @@ jungrapht.satelliteBackgroundTransparent=false
|
||||||
jungrapht.satelliteLensColor= 0xFAFAFA
|
jungrapht.satelliteLensColor= 0xFAFAFA
|
||||||
|
|
||||||
jungrapht.pickedEdgeColor=0xFF0000
|
jungrapht.pickedEdgeColor=0xFF0000
|
||||||
jungrapht.edgeArrowLength=30
|
jungrapht.edgeArrowLength=50
|
||||||
jungrapht.edgeArrowWidth=20
|
jungrapht.edgeArrowWidth=40
|
||||||
|
|
||||||
# default spacing for tree layouts
|
# default spacing for tree layouts
|
||||||
jungrapht.treeLayoutHorizontalSpacing=2
|
jungrapht.treeLayoutHorizontalSpacing=2
|
||||||
|
@ -34,7 +34,7 @@ jungrapht.lensStrokeWidth=10.0
|
||||||
# when scale is < .1, switch to lightweight rendering
|
# when scale is < .1, switch to lightweight rendering
|
||||||
jungrapht.lightweightScaleThreshold=.1
|
jungrapht.lightweightScaleThreshold=.1
|
||||||
# under 50 vertices will use heavyweight rendering all the time
|
# under 50 vertices will use heavyweight rendering all the time
|
||||||
jungrapht.lightweightCountThreshold=50
|
jungrapht.lightweightCountThreshold=80
|
||||||
|
|
||||||
# default pixels spacings for vertices
|
# default pixels spacings for vertices
|
||||||
jungrapht.mincross.horizontalOffset=10
|
jungrapht.mincross.horizontalOffset=10
|
||||||
|
@ -69,12 +69,12 @@ jungrapht.edgeSpatialSupport=RTREE
|
||||||
# the mask for single vertex/edge selection
|
# the mask for single vertex/edge selection
|
||||||
jungrapht.singleSelectionMask=MB1
|
jungrapht.singleSelectionMask=MB1
|
||||||
# the mask to augment the selection with a single vertex/edge
|
# the mask to augment the selection with a single vertex/edge
|
||||||
jungrapht.addSingleSelectionMask=MB1_MENU
|
jungrapht.toggleSingleSelectionMask=MB1_MENU
|
||||||
# the mask to select vertices within a region
|
# the mask to select vertices within a region
|
||||||
jungrapht.regionSelectionMask=MB1_MENU
|
jungrapht.regionSelectionMask=MB1_MENU
|
||||||
# the mask to augment the selection with vertices in a region
|
# the mask to augment the selection with vertices in a region
|
||||||
jungrapht.addRegionSelectionMask=MB1_SHIFT_MENU
|
jungrapht.toggleRegionSelectionMask=MB1_SHIFT_MENU
|
||||||
# the mask to indicate that the selection region is complete/closed and selection may commence
|
# the mask to indicate that the selection region is complete/closed and selection may commence
|
||||||
jungrapht.regionSelectionCompleteMask=MENU
|
jungrapht.regionSelectionCompleteMask=MENU
|
||||||
# the mask to indicate that the selection region for augmentation is complete/closed and selection may commence
|
# the mask to indicate that the selection region for augmentation is complete/closed and selection may commence
|
||||||
jungrapht.addRegionSelectionCompleteMask=SHIFT_MENU
|
jungrapht.toggleRegionSelectionCompleteMask=SHIFT_MENU
|
||||||
|
|
|
@ -34,6 +34,52 @@ public interface GraphDisplay {
|
||||||
public static final int ALIGN_CENTER = 1; // aligns graph text to the center
|
public static final int ALIGN_CENTER = 1; // aligns graph text to the center
|
||||||
public static final int ALIGN_RIGHT = 2; // aligns graph text to the right
|
public static final int ALIGN_RIGHT = 2; // aligns graph text to the right
|
||||||
|
|
||||||
|
/**
|
||||||
|
* values are color names or rgb in hex '0xFF0000' is red
|
||||||
|
*/
|
||||||
|
String SELECTED_VERTEX_COLOR = "selectedVertexColor";
|
||||||
|
/**
|
||||||
|
* values are color names or rgb in hex '0xFF0000' is red
|
||||||
|
*/
|
||||||
|
String SELECTED_EDGE_COLOR = "selectedEdgeColor";
|
||||||
|
/**
|
||||||
|
* values are defined as String symbols in LayoutFunction class
|
||||||
|
*
|
||||||
|
* KAMADA_KAWAI,FRUCTERMAN_REINGOLD,CIRCLE_MINCROSS,TIDIER_TREE,TIDIER_RADIAL_TREE,
|
||||||
|
* MIN_CROSS_TOP_DOWN,MIN_CROSS_LONGEST_PATH,MIN_CROSS_NETWORK_SIMPLEX,MIN_CROSS_COFFMAN_GRAHAM,
|
||||||
|
* EXP_MIN_CROSS_TOP_DOWN,EXP_MIN_CROSS_LONGEST_PATH,EXP_MIN_CROSS_NETWORK_SIMPLEX,
|
||||||
|
* EXP_MIN_CROSS_COFFMAN_GRAHAM,TREE,RADIAL,BALLOON,GEM
|
||||||
|
*
|
||||||
|
* may have no meaning for a different graph visualization library
|
||||||
|
*/
|
||||||
|
String INITIAL_LAYOUT_ALGORITHM = "initialLayoutAlgorithm";
|
||||||
|
/**
|
||||||
|
* true or false
|
||||||
|
* may have no meaning for a different graph visualization library
|
||||||
|
*/
|
||||||
|
String DISPLAY_VERTICES_AS_ICONS = "displayVerticesAsIcons";
|
||||||
|
/**
|
||||||
|
* values are the strings N,NE,E,SE,S,SW,W,NW,AUTO,CNTR
|
||||||
|
* may have no meaning for a different graph visualization library
|
||||||
|
*/
|
||||||
|
String VERTEX_LABEL_POSITION = "vertexLabelPosition";
|
||||||
|
/**
|
||||||
|
* true or false, whether edge selection via a mouse click is enabled.
|
||||||
|
* May not be supported by another graph visualization library
|
||||||
|
*/
|
||||||
|
String ENABLE_EDGE_SELECTION = "enableEdgeSelection";
|
||||||
|
/**
|
||||||
|
* a comma-separated list of edge type names in priority order
|
||||||
|
*/
|
||||||
|
String EDGE_TYPE_PRIORITY_LIST = "edgeTypePriorityList";
|
||||||
|
/**
|
||||||
|
* a comma-separated list of edge type names.
|
||||||
|
* any will be considered a favored edge for the min-cross layout
|
||||||
|
* algorithms.
|
||||||
|
* May have no meaning with a different graph visualization library
|
||||||
|
*/
|
||||||
|
String FAVORED_EDGES = "favoredEdges";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets a {@link GraphDisplayListener} to be notified when the user changes the vertex focus
|
* Sets a {@link GraphDisplayListener} to be notified when the user changes the vertex focus
|
||||||
* or selects one or more nodes in a graph window
|
* or selects one or more nodes in a graph window
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue