From 5575cce93740b8b81a601e32454e8ca8936a8907 Mon Sep 17 00:00:00 2001 From: tom Date: Fri, 15 May 2020 07:57:25 -0400 Subject: [PATCH] updated jungrapht-visualization to 1.0-RC8. Includes fixes noted in functional review. Adds additional layering algorithms to mincross layout algorithm. Fix Module.manifest versions --- Ghidra/Features/GraphServices/Module.manifest | 6 +-- Ghidra/Features/GraphServices/build.gradle | 3 +- .../visualization/DefaultGraphDisplay.java | 8 +--- .../graph/visualization/GhidraIconCache.java | 5 ++- .../graph/visualization/LayoutFunction.java | 42 ++++++++++++++----- .../LayoutTransitionManager.java | 2 +- .../src/main/resources/jungrapht.properties | 2 +- 7 files changed, 43 insertions(+), 25 deletions(-) diff --git a/Ghidra/Features/GraphServices/Module.manifest b/Ghidra/Features/GraphServices/Module.manifest index 2a754f3992..c6514259dd 100644 --- a/Ghidra/Features/GraphServices/Module.manifest +++ b/Ghidra/Features/GraphServices/Module.manifest @@ -1,7 +1,7 @@ EXCLUDE FROM GHIDRA JAR: true -MODULE FILE LICENSE: lib/jungrapht-visualization-2.11.20 BSD -MODULE FILE LICENSE: lib/jgrapht-core-1.3.1.jar LGPL 2.1 -MODULE FILE LICENSE: lib/jgrapht-io-1.3.1.jar LGPL 2.1 +MODULE FILE LICENSE: lib/jungrapht-visualization-1.0-RC8 BSD +MODULE FILE LICENSE: lib/jgrapht-core-1.4.0.jar LGPL 2.1 +MODULE FILE LICENSE: lib/jgrapht-io-1.4.0.jar LGPL 2.1 MODULE FILE LICENSE: lib/jheaps-0.10.jar Apache License 2.0 MODULE FILE LICENSE: lib/slf4j-api-1.7.25.jar MIT diff --git a/Ghidra/Features/GraphServices/build.gradle b/Ghidra/Features/GraphServices/build.gradle index abc1114f66..55ce5ae4f0 100644 --- a/Ghidra/Features/GraphServices/build.gradle +++ b/Ghidra/Features/GraphServices/build.gradle @@ -11,12 +11,13 @@ eclipse.project.name = 'Features Graph Services' dependencies { compile project(":Base") - compile "com.github.tomnelson:jungrapht-visualization:1.0-RC7" + compile "com.github.tomnelson:jungrapht-visualization:1.0-RC8" compile "org.jgrapht:jgrapht-core:1.4.0" // not using jgrapht-io code that depends on antlr, so exclude antlr compile ("org.jgrapht:jgrapht-io:1.4.0") { exclude group: "org.antlr", module: "antlr4-runtime" } runtime "org.slf4j:slf4j-api:1.7.25" + runtime "org.slf4j:slf4j-nop:1.7.25" runtime "org.jheaps:jheaps:0.11" helpPath project(path: ":Base", configuration: 'helpPath') diff --git a/Ghidra/Features/GraphServices/src/main/java/ghidra/graph/visualization/DefaultGraphDisplay.java b/Ghidra/Features/GraphServices/src/main/java/ghidra/graph/visualization/DefaultGraphDisplay.java index 02198e622c..cc5072f2e3 100644 --- a/Ghidra/Features/GraphServices/src/main/java/ghidra/graph/visualization/DefaultGraphDisplay.java +++ b/Ghidra/Features/GraphServices/src/main/java/ghidra/graph/visualization/DefaultGraphDisplay.java @@ -229,7 +229,7 @@ public class DefaultGraphDisplay implements GraphDisplay { .toolBarIcon(Icons.REFRESH_ICON) .onAction(context -> { viewer.reset(); - viewer.scaleToLayout(); + viewer.scaleToLayout(true); }) .buildAndInstallLocal(componentProvider); @@ -345,17 +345,13 @@ public class DefaultGraphDisplay implements GraphDisplay { Collection selectedVertices = getVertices(e.getItem()); List selectedVertexIds = toVertexIds(selectedVertices); notifySelectionChanged(selectedVertexIds); - multiSelectedVertexPaintable.setSelectedVertices(selectedVertices); AttributedVertex vertex = CollectionUtils.any(selectedVertices); if (vertex != null) { - singleSelectedVertexPaintable.setSelectedVertex(vertex); notifyLocationChanged(vertex.getId()); } } else if (e.getStateChange() == ItemEvent.DESELECTED) { - singleSelectedVertexPaintable.setSelectedVertex(null); - multiSelectedVertexPaintable.setSelectedVertices(Collections.emptySet()); notifySelectionChanged(Collections.emptyList()); } viewer.repaint(); @@ -399,7 +395,6 @@ public class DefaultGraphDisplay implements GraphDisplay { else if (!Arrays.asList(nodeSelectedState.getSelectedObjects()).containsAll(selected)) { nodeSelectedState.clear(); nodeSelectedState.select(selected, false); - multiSelectedVertexPaintable.setSelectedVertices(selected); scrollToSelected(selected); } viewer.repaint(); @@ -418,7 +413,6 @@ public class DefaultGraphDisplay implements GraphDisplay { Optional selected = graph.vertexSet().stream().filter(v -> vertexID.equals(v.getId())).findFirst(); log.fine("picking address:" + vertexID + " returned " + selected); - singleSelectedVertexPaintable.setSelectedVertex(selected.orElse(null)); viewer.repaint(); selected.ifPresent(this::scrollToSelected); viewer.repaint(); diff --git a/Ghidra/Features/GraphServices/src/main/java/ghidra/graph/visualization/GhidraIconCache.java b/Ghidra/Features/GraphServices/src/main/java/ghidra/graph/visualization/GhidraIconCache.java index 10112d5f46..4dafd4eb44 100644 --- a/Ghidra/Features/GraphServices/src/main/java/ghidra/graph/visualization/GhidraIconCache.java +++ b/Ghidra/Features/GraphServices/src/main/java/ghidra/graph/visualization/GhidraIconCache.java @@ -31,7 +31,8 @@ import ghidra.service.graph.AttributedVertex; public class GhidraIconCache { private static final int DEFAULT_STROKE_THICKNESS = 8; - private static final int DEFAULT_FONT_SIZE = 20; + private static final int DEFAULT_FONT_SIZE = 12; + private static final String DEFAULT_FONT_NAME = "Dialog"; private static final int DEFAULT_MARGIN_BORDER_SIZE = 4; private static final float LABEL_TO_ICON_PROPORTION_WAG = 1.4f; private static final double SQRT_2 = Math.sqrt(2.0); @@ -64,7 +65,7 @@ public class GhidraIconCache { private Icon createIcon(AttributedVertex vertex) { rendererLabel.setText(ProgramGraphFunctions.getLabel(vertex)); - rendererLabel.setFont(new Font("Serif", Font.BOLD, DEFAULT_FONT_SIZE)); + rendererLabel.setFont(new Font(DEFAULT_FONT_NAME, Font.BOLD, DEFAULT_FONT_SIZE)); rendererLabel.setForeground(Color.black); rendererLabel.setBackground(Color.white); rendererLabel.setOpaque(true); diff --git a/Ghidra/Features/GraphServices/src/main/java/ghidra/graph/visualization/LayoutFunction.java b/Ghidra/Features/GraphServices/src/main/java/ghidra/graph/visualization/LayoutFunction.java index e7a4d3bb41..1e469596c2 100644 --- a/Ghidra/Features/GraphServices/src/main/java/ghidra/graph/visualization/LayoutFunction.java +++ b/Ghidra/Features/GraphServices/src/main/java/ghidra/graph/visualization/LayoutFunction.java @@ -15,7 +15,11 @@ */ package ghidra.graph.visualization; +import java.util.function.Function; + import org.jungrapht.visualization.layout.algorithms.*; +import org.jungrapht.visualization.layout.algorithms.sugiyama.Layering; + import org.jungrapht.visualization.layout.algorithms.repulsion.BarnesHutFRRepulsion; import ghidra.service.graph.AttributedEdge; @@ -28,24 +32,30 @@ import ghidra.service.graph.AttributedVertex; * This class provides LayoutAlgorithm builders instead of LayoutAlgorithms because some LayoutAlgorithms * accumulate state information (so are used only one time). */ -class LayoutFunction { +class LayoutFunction + implements Function> { static final String KAMADA_KAWAI = "Force Balanced"; static final String FRUCTERMAN_REINGOLD = "Force Directed"; static final String CIRCLE_MINCROSS = "Circle"; static final String TIDIER_TREE = "Compact Hierarchical"; - static final String MIN_CROSS = "Hierarchical Min Cross"; + 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_NETWORK_SIMPLEX = "Hierarchical MinCross Network Simplex"; + static final String MIN_CROSS_COFFMAN_GRAHAM = "Hierarchical MinCross Coffman Graham"; static final String MULTI_ROW_EDGE_AWARE_TREE = "Hierarchical MultiRow"; static final String EDGE_AWARE_TREE = "Hierarchical"; static final String EDGE_AWARE_RADIAL = "Radial"; public String[] getNames() { - return new String[] { KAMADA_KAWAI, FRUCTERMAN_REINGOLD, CIRCLE_MINCROSS, TIDIER_TREE, MIN_CROSS, - MULTI_ROW_EDGE_AWARE_TREE, EDGE_AWARE_TREE, EDGE_AWARE_RADIAL}; + return new String[] { EDGE_AWARE_TREE, MULTI_ROW_EDGE_AWARE_TREE, TIDIER_TREE, + MIN_CROSS_TOP_DOWN, MIN_CROSS_LONGEST_PATH, MIN_CROSS_NETWORK_SIMPLEX, + MIN_CROSS_COFFMAN_GRAHAM, CIRCLE_MINCROSS, KAMADA_KAWAI, FRUCTERMAN_REINGOLD, + EDGE_AWARE_RADIAL }; } - public LayoutAlgorithm.Builder apply( - String name) { + @Override + public LayoutAlgorithm.Builder apply(String name) { switch(name) { case KAMADA_KAWAI: return KKLayoutAlgorithm. builder().preRelaxDuration(1000); @@ -54,14 +64,25 @@ class LayoutFunction { .repulsionContractBuilder(BarnesHutFRRepulsion.barnesHutBuilder()); case CIRCLE_MINCROSS: return CircleLayoutAlgorithm. builder() - .threaded(true) .reduceEdgeCrossing(true); case TIDIER_TREE: return TidierTreeLayoutAlgorithm. edgeAwareBuilder(); - case MIN_CROSS: + case MIN_CROSS_TOP_DOWN: return HierarchicalMinCrossLayoutAlgorithm . edgeAwareBuilder() - .threaded(true); + .layering(Layering.TOP_DOWN); + case MIN_CROSS_LONGEST_PATH: + return EiglspergerLayoutAlgorithm + . edgeAwareBuilder() + .layering(Layering.LONGEST_PATH); + case MIN_CROSS_NETWORK_SIMPLEX: + return EiglspergerLayoutAlgorithm + . edgeAwareBuilder() + .layering(Layering.NETWORK_SIMPLEX); + case MIN_CROSS_COFFMAN_GRAHAM: + return EiglspergerLayoutAlgorithm + . edgeAwareBuilder() + .layering(Layering.COFFMAN_GRAHAM); case MULTI_ROW_EDGE_AWARE_TREE: return MultiRowEdgeAwareTreeLayoutAlgorithm . edgeAwareBuilder(); @@ -71,7 +92,8 @@ class LayoutFunction { .verticalVertexSpacing(300); case EDGE_AWARE_TREE: default: - return EdgeAwareTreeLayoutAlgorithm. edgeAwareBuilder(); + return EdgeAwareTreeLayoutAlgorithm + . edgeAwareBuilder(); } } } diff --git a/Ghidra/Features/GraphServices/src/main/java/ghidra/graph/visualization/LayoutTransitionManager.java b/Ghidra/Features/GraphServices/src/main/java/ghidra/graph/visualization/LayoutTransitionManager.java index 17b33f6885..d89efe63e2 100644 --- a/Ghidra/Features/GraphServices/src/main/java/ghidra/graph/visualization/LayoutTransitionManager.java +++ b/Ghidra/Features/GraphServices/src/main/java/ghidra/graph/visualization/LayoutTransitionManager.java @@ -58,7 +58,7 @@ class LayoutTransitionManager { /** * a {@link Comparator} to sort edges during layout graph traversal */ - Comparator edgeComparator; + Comparator edgeComparator = (e1, e2) -> 0; /** * a {@link MultiActionDockingAction} to allow the user to select a layout algorithm diff --git a/Ghidra/Features/GraphServices/src/main/resources/jungrapht.properties b/Ghidra/Features/GraphServices/src/main/resources/jungrapht.properties index 3daf634a0e..09aaedc129 100644 --- a/Ghidra/Features/GraphServices/src/main/resources/jungrapht.properties +++ b/Ghidra/Features/GraphServices/src/main/resources/jungrapht.properties @@ -27,7 +27,7 @@ jungrapht.edgeWidth=4.0f # stroke size for the magnifier lens jungrapht.lensStrokeWidth=10.0 # when scale is < .3, switch to lightweight rendering -jungrapht.lightweightScaleThreshold=.3 +jungrapht.lightweightScaleThreshold=.8 # under 50 vertices will use heavyweight rendering all the time jungrapht.lightweightCountThreshold=50