mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-10-06 03:50:02 +02:00
GT-3019 - Function Graph - Added option for edge routing around vertices
This commit is contained in:
parent
ac98e609d7
commit
a04185e942
24 changed files with 933 additions and 259 deletions
|
@ -48,7 +48,6 @@ import ghidra.program.model.listing.Function;
|
|||
import ghidra.program.util.ProgramLocation;
|
||||
import ghidra.program.util.ProgramSelection;
|
||||
import ghidra.util.*;
|
||||
import ghidra.util.exception.AssertException;
|
||||
import resources.Icons;
|
||||
import resources.ResourceManager;
|
||||
|
||||
|
@ -72,7 +71,6 @@ class FGActionManager {
|
|||
private MultiStateDockingAction<EdgeDisplayType> vertexHoverModeAction;
|
||||
private MultiStateDockingAction<EdgeDisplayType> vertexFocusModeAction;
|
||||
|
||||
private FGLayoutFinder layoutFinder = new DiscoverableFGLayoutFinder();
|
||||
private MultiStateDockingAction<Class<? extends FGLayoutProvider>> layoutAction;
|
||||
|
||||
FGActionManager(FunctionGraphPlugin plugin, FGController controller, FGProvider provider) {
|
||||
|
@ -857,8 +855,7 @@ class FGActionManager {
|
|||
HelpLocation layoutHelpLocation =
|
||||
new HelpLocation("FunctionGraphPlugin", "Function_Graph_Action_Layout");
|
||||
|
||||
layoutAction = new MultiStateDockingAction<Class<? extends FGLayoutProvider>>(
|
||||
"Relayout Graph", plugin.getName()) {
|
||||
layoutAction = new MultiStateDockingAction<>("Relayout Graph", plugin.getName()) {
|
||||
|
||||
@Override
|
||||
protected void doActionPerformed(ActionContext context) {
|
||||
|
@ -901,20 +898,12 @@ class FGActionManager {
|
|||
|
||||
private List<ActionState<Class<? extends FGLayoutProvider>>> loadActionStatesForLayoutProviders() {
|
||||
|
||||
Set<FGLayoutProvider> instances = layoutFinder.findLayouts();
|
||||
if (instances.isEmpty()) {
|
||||
throw new AssertException("Could not find any layout providers. You project may not " +
|
||||
"be configured properly.");
|
||||
}
|
||||
|
||||
List<FGLayoutProvider> layoutInstances = new ArrayList<>(instances);
|
||||
Collections.sort(layoutInstances,
|
||||
(o1, o2) -> -o1.getPriorityLevel() + o2.getPriorityLevel());
|
||||
|
||||
List<FGLayoutProvider> layoutInstances = plugin.getLayoutProviders();
|
||||
List<ActionState<Class<? extends FGLayoutProvider>>> list = new ArrayList<>();
|
||||
HelpLocation layoutHelpLocation =
|
||||
new HelpLocation("FunctionGraphPlugin", "Function_Graph_Action_Layout");
|
||||
for (FGLayoutProvider layout : layoutInstances) {
|
||||
|
||||
ActionState<Class<? extends FGLayoutProvider>> layoutState = new ActionState<>(
|
||||
layout.getLayoutName(), layout.getActionIcon(), layout.getClass());
|
||||
layoutState.setHelpLocation(layoutHelpLocation);
|
||||
|
@ -996,7 +985,7 @@ class FGActionManager {
|
|||
offState.setHelpLocation(pathHelpLocation);
|
||||
|
||||
vertexHoverModeAction =
|
||||
new MultiStateDockingAction<EdgeDisplayType>("Block Hover Mode", plugin.getName()) {
|
||||
new MultiStateDockingAction<>("Block Hover Mode", plugin.getName()) {
|
||||
|
||||
@Override
|
||||
public void actionStateChanged(ActionState<EdgeDisplayType> newActionState,
|
||||
|
@ -1065,7 +1054,7 @@ class FGActionManager {
|
|||
offState.setHelpLocation(pathHelpLocation);
|
||||
|
||||
vertexFocusModeAction =
|
||||
new MultiStateDockingAction<EdgeDisplayType>("Block Focus Mode", plugin.getName()) {
|
||||
new MultiStateDockingAction<>("Block Focus Mode", plugin.getName()) {
|
||||
|
||||
@Override
|
||||
public void actionStateChanged(ActionState<EdgeDisplayType> newActionState,
|
||||
|
@ -1204,10 +1193,6 @@ class FGActionManager {
|
|||
}
|
||||
}
|
||||
|
||||
void setLayoutFinder(FGLayoutFinder layoutFinder) {
|
||||
this.layoutFinder = layoutFinder;
|
||||
}
|
||||
|
||||
void setEdgeFocusMode(EdgeDisplayType edgeDisplayType) {
|
||||
vertexFocusModeAction.setCurrentActionStateByUserData(edgeDisplayType);
|
||||
}
|
||||
|
|
|
@ -27,6 +27,8 @@ import ghidra.app.events.*;
|
|||
import ghidra.app.plugin.PluginCategoryNames;
|
||||
import ghidra.app.plugin.ProgramPlugin;
|
||||
import ghidra.app.plugin.core.colorizer.ColorizingService;
|
||||
import ghidra.app.plugin.core.functiongraph.graph.layout.FGLayoutOptions;
|
||||
import ghidra.app.plugin.core.functiongraph.graph.layout.FGLayoutProvider;
|
||||
import ghidra.app.plugin.core.functiongraph.mvc.FunctionGraphOptions;
|
||||
import ghidra.app.services.*;
|
||||
import ghidra.app.util.viewer.format.FormatManager;
|
||||
|
@ -40,6 +42,7 @@ import ghidra.graph.viewer.options.VisualGraphOptions;
|
|||
import ghidra.program.model.listing.Program;
|
||||
import ghidra.program.util.ProgramLocation;
|
||||
import ghidra.program.util.ProgramSelection;
|
||||
import ghidra.util.exception.AssertException;
|
||||
import resources.ResourceManager;
|
||||
|
||||
//@formatter:off
|
||||
|
@ -78,6 +81,7 @@ public class FunctionGraphPlugin extends ProgramPlugin implements OptionsChangeL
|
|||
private FunctionGraphOptions functionGraphOptions = new FunctionGraphOptions();
|
||||
|
||||
private FGColorProvider colorProvider;
|
||||
private List<FGLayoutProvider> layoutProviders;
|
||||
|
||||
public FunctionGraphPlugin(PluginTool tool) {
|
||||
super(tool, true, true, true);
|
||||
|
@ -88,6 +92,9 @@ public class FunctionGraphPlugin extends ProgramPlugin implements OptionsChangeL
|
|||
@Override
|
||||
protected void init() {
|
||||
super.init();
|
||||
|
||||
layoutProviders = loadLayoutProviders();
|
||||
|
||||
createNewProvider();
|
||||
initializeOptions();
|
||||
|
||||
|
@ -125,17 +132,44 @@ public class FunctionGraphPlugin extends ProgramPlugin implements OptionsChangeL
|
|||
}
|
||||
}
|
||||
|
||||
private List<FGLayoutProvider> loadLayoutProviders() {
|
||||
|
||||
FGLayoutFinder layoutFinder = new DiscoverableFGLayoutFinder();
|
||||
Set<FGLayoutProvider> instances = layoutFinder.findLayouts();
|
||||
if (instances.isEmpty()) {
|
||||
throw new AssertException("Could not find any layout providers. You project may not " +
|
||||
"be configured properly.");
|
||||
}
|
||||
|
||||
List<FGLayoutProvider> layouts = new ArrayList<>(instances);
|
||||
Collections.sort(layouts, (o1, o2) -> -o1.getPriorityLevel() + o2.getPriorityLevel());
|
||||
return layouts;
|
||||
}
|
||||
|
||||
private void initializeOptions() {
|
||||
ToolOptions options = tool.getOptions(PLUGIN_OPTIONS_NAME);
|
||||
options.addOptionsChangeListener(this);
|
||||
functionGraphOptions.initializeOptions(this, options);
|
||||
functionGraphOptions.loadOptions(this, options);
|
||||
functionGraphOptions.registerOptions(options);
|
||||
functionGraphOptions.loadOptions(options);
|
||||
|
||||
for (FGLayoutProvider layoutProvider : layoutProviders) {
|
||||
String layoutName = layoutProvider.getLayoutName();
|
||||
Options layoutToolOptions = options.getOptions(layoutName);
|
||||
FGLayoutOptions layoutOptions = layoutProvider.createLayoutOptions(layoutToolOptions);
|
||||
if (layoutOptions == null) {
|
||||
continue; // many layouts do not have options
|
||||
}
|
||||
|
||||
layoutOptions.registerOptions(layoutToolOptions);
|
||||
layoutOptions.loadOptions(layoutToolOptions);
|
||||
functionGraphOptions.setLayoutOptions(layoutName, layoutOptions);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void optionsChanged(ToolOptions options, String optionName, Object oldValue,
|
||||
Object newValue) {
|
||||
functionGraphOptions.loadOptions(this, options);
|
||||
functionGraphOptions.loadOptions(options);
|
||||
connectedProvider.getComponent().repaint();
|
||||
for (FGProvider provider : disconnectedProviders) {
|
||||
provider.getComponent().repaint();
|
||||
|
@ -383,14 +417,6 @@ public class FunctionGraphPlugin extends ProgramPlugin implements OptionsChangeL
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dataStateRestoreCompleted() {
|
||||
super.dataStateRestoreCompleted();
|
||||
// ProgramLocation location = ProgramLocation.getLocation(
|
||||
// currentProgram, dataSaveState, null );
|
||||
|
||||
}
|
||||
|
||||
public FGColorProvider getColorProvider() {
|
||||
return colorProvider;
|
||||
}
|
||||
|
@ -399,4 +425,7 @@ public class FunctionGraphPlugin extends ProgramPlugin implements OptionsChangeL
|
|||
return functionGraphOptions;
|
||||
}
|
||||
|
||||
public List<FGLayoutProvider> getLayoutProviders() {
|
||||
return Collections.unmodifiableList(layoutProviders);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -37,8 +37,8 @@ public abstract class AbstractFGLayout extends AbstractVisualGraphLayout<FGVerte
|
|||
protected Function function;
|
||||
protected FunctionGraphOptions options;
|
||||
|
||||
protected AbstractFGLayout(FunctionGraph graph) {
|
||||
super(graph);
|
||||
protected AbstractFGLayout(FunctionGraph graph, String layoutName) {
|
||||
super(graph, layoutName);
|
||||
this.function = graph.getFunction();
|
||||
this.options = graph.getOptions();
|
||||
}
|
||||
|
|
|
@ -34,8 +34,10 @@ import ghidra.util.task.TaskMonitor;
|
|||
|
||||
public class EmptyLayout extends AbstractVisualGraphLayout<FGVertex, FGEdge> implements FGLayout {
|
||||
|
||||
private static final String NAME = "Empty Layout";
|
||||
|
||||
public EmptyLayout(FunctionGraph graph) {
|
||||
super(graph);
|
||||
super(graph, NAME);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -19,7 +19,7 @@ import javax.swing.Icon;
|
|||
|
||||
import resources.ResourceManager;
|
||||
|
||||
public abstract class ExperimentalLayoutProvider implements FGLayoutProvider {
|
||||
public abstract class ExperimentalLayoutProvider extends FGLayoutProvider {
|
||||
|
||||
private static final Icon ICON = ResourceManager.loadImage("images/package_development.png");
|
||||
|
||||
|
|
|
@ -0,0 +1,43 @@
|
|||
/* ###
|
||||
* IP: GHIDRA
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package ghidra.app.plugin.core.functiongraph.graph.layout;
|
||||
|
||||
import ghidra.app.plugin.core.functiongraph.FunctionGraphPlugin;
|
||||
import ghidra.framework.options.Options;
|
||||
|
||||
/**
|
||||
* An interface for {@link FGLayout} options
|
||||
*/
|
||||
public interface FGLayoutOptions {
|
||||
|
||||
public static final String OWNER = FunctionGraphPlugin.class.getSimpleName();
|
||||
|
||||
/**
|
||||
* Called during setup for this class to register its options with the given {@link Options}
|
||||
* object
|
||||
*
|
||||
* @param options the tool options
|
||||
*/
|
||||
public void registerOptions(Options options);
|
||||
|
||||
/**
|
||||
* Called when the given {@link Options} object has changed. This class will update its
|
||||
* options with the values from the given options object.
|
||||
*
|
||||
* @param options the tool options
|
||||
*/
|
||||
public void loadOptions(Options options);
|
||||
}
|
|
@ -18,20 +18,30 @@ package ghidra.app.plugin.core.functiongraph.graph.layout;
|
|||
import ghidra.app.plugin.core.functiongraph.graph.FGEdge;
|
||||
import ghidra.app.plugin.core.functiongraph.graph.FunctionGraph;
|
||||
import ghidra.app.plugin.core.functiongraph.graph.vertex.FGVertex;
|
||||
import ghidra.framework.options.Options;
|
||||
import ghidra.graph.viewer.layout.LayoutProvider;
|
||||
import ghidra.util.exception.CancelledException;
|
||||
import ghidra.util.task.TaskMonitor;
|
||||
|
||||
public interface FGLayoutProvider extends LayoutProvider<FGVertex, FGEdge, FunctionGraph> {
|
||||
public abstract class FGLayoutProvider implements LayoutProvider<FGVertex, FGEdge, FunctionGraph> {
|
||||
|
||||
public abstract FGLayout getFGLayout(FunctionGraph graph, TaskMonitor monitor)
|
||||
throws CancelledException;
|
||||
|
||||
// Suppressing warning on the return type; we know our class is the right type
|
||||
@Override
|
||||
public default FGLayout getLayout(FunctionGraph graph, TaskMonitor monitor)
|
||||
throws CancelledException {
|
||||
|
||||
public FGLayout getLayout(FunctionGraph graph, TaskMonitor monitor) throws CancelledException {
|
||||
return getFGLayout(graph, monitor);
|
||||
}
|
||||
|
||||
public FGLayout getFGLayout(FunctionGraph graph, TaskMonitor monitor) throws CancelledException;
|
||||
|
||||
/**
|
||||
* Creates an options object for layouts created by this provider. Returns null if there
|
||||
* are not options for layouts created by this provider.
|
||||
*
|
||||
* @param options the tool options into which layout options should be registered
|
||||
* @return the new options; null if there are no options
|
||||
*/
|
||||
public FGLayoutOptions createLayoutOptions(Options options) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -16,15 +16,20 @@
|
|||
package ghidra.app.plugin.core.functiongraph.mvc;
|
||||
|
||||
import java.awt.Color;
|
||||
import java.util.*;
|
||||
import java.util.Map.Entry;
|
||||
|
||||
import ghidra.framework.options.ToolOptions;
|
||||
import ghidra.framework.plugintool.Plugin;
|
||||
import ghidra.app.plugin.core.functiongraph.FunctionGraphPlugin;
|
||||
import ghidra.app.plugin.core.functiongraph.graph.layout.FGLayoutOptions;
|
||||
import ghidra.framework.options.Options;
|
||||
import ghidra.graph.viewer.options.*;
|
||||
import ghidra.program.model.symbol.FlowType;
|
||||
import ghidra.util.HelpLocation;
|
||||
|
||||
public class FunctionGraphOptions extends VisualGraphOptions {
|
||||
|
||||
protected static final String OWNER = FunctionGraphPlugin.class.getSimpleName();
|
||||
|
||||
private static final String EDGE_FALLTHROUGH_HIGHLIGHT_COLOR_KEY =
|
||||
"Edge Color - Fallthrough Highlight";
|
||||
private static final String EDGE_UNCONDITIONAL_JUMP_HIGHLIGHT_COLOR_KEY =
|
||||
|
@ -48,7 +53,7 @@ public class FunctionGraphOptions extends VisualGraphOptions {
|
|||
|
||||
private static final String DEFAULT_GROUP_BACKGROUND_COLOR_KEY = "Default Group Color";
|
||||
private static final String DEFAULT_GROUP_BACKGROUND_COLOR_DESCRPTION =
|
||||
"The default " + "background color applied to newly created group vertices";
|
||||
"The default background color applied to newly created group vertices";
|
||||
|
||||
private static final String UPDATE_GROUP_AND_UNGROUP_COLORS =
|
||||
"Update Vertex Colors When Grouping";
|
||||
|
@ -74,6 +79,8 @@ public class FunctionGraphOptions extends VisualGraphOptions {
|
|||
|
||||
protected RelayoutOption relayoutOption = RelayoutOption.NEVER;
|
||||
|
||||
private Map<String, FGLayoutOptions> layoutOptionsByName = new HashMap<>();
|
||||
|
||||
public Color getDefaultGroupBackgroundColor() {
|
||||
return defaultGroupBackgroundColor;
|
||||
}
|
||||
|
@ -110,8 +117,9 @@ public class FunctionGraphOptions extends VisualGraphOptions {
|
|||
return relayoutOption;
|
||||
}
|
||||
|
||||
public void initializeOptions(Plugin plugin, ToolOptions options) {
|
||||
HelpLocation help = new HelpLocation(plugin.getName(), "Options");
|
||||
public void registerOptions(Options options) {
|
||||
|
||||
HelpLocation help = new HelpLocation(OWNER, "Options");
|
||||
options.setOptionsHelpLocation(help);
|
||||
|
||||
options.registerOption(RELAYOUT_OPTIONS_KEY, RelayoutOption.VERTEX_GROUPING_CHANGES, help,
|
||||
|
@ -124,8 +132,7 @@ public class FunctionGraphOptions extends VisualGraphOptions {
|
|||
USE_MOUSE_RELATIVE_ZOOM_DESCRIPTION);
|
||||
|
||||
options.registerOption(USE_CONDENSED_LAYOUT, useCondensedLayout(),
|
||||
new HelpLocation(plugin.getName(), "Layout_Compressing"),
|
||||
USE_CONDENSED_LAYOUT_DESCRIPTION);
|
||||
new HelpLocation(OWNER, "Layout_Compressing"), USE_CONDENSED_LAYOUT_DESCRIPTION);
|
||||
|
||||
options.registerOption(VIEW_RESTORE_OPTIONS_KEY, ViewRestoreOption.START_FULLY_ZOOMED_OUT,
|
||||
help, VIEW_RESTORE_OPTIONS_DESCRIPTION);
|
||||
|
@ -161,7 +168,7 @@ public class FunctionGraphOptions extends VisualGraphOptions {
|
|||
|
||||
}
|
||||
|
||||
public void loadOptions(Plugin plugin, ToolOptions options) {
|
||||
public void loadOptions(Options options) {
|
||||
conditionalJumpEdgeColor =
|
||||
options.getColor(EDGE_COLOR_CONDITIONAL_JUMP_KEY, conditionalJumpEdgeColor);
|
||||
|
||||
|
@ -198,6 +205,14 @@ public class FunctionGraphOptions extends VisualGraphOptions {
|
|||
|
||||
updateGroupColorsAutomatically =
|
||||
options.getBoolean(UPDATE_GROUP_AND_UNGROUP_COLORS, updateGroupColorsAutomatically);
|
||||
|
||||
Set<Entry<String, FGLayoutOptions>> entries = layoutOptionsByName.entrySet();
|
||||
for (Entry<String, FGLayoutOptions> entry : entries) {
|
||||
String layoutName = entry.getKey();
|
||||
FGLayoutOptions layoutOptions = entry.getValue();
|
||||
Options layoutToolOptions = options.getOptions(layoutName);
|
||||
layoutOptions.loadOptions(layoutToolOptions);
|
||||
}
|
||||
}
|
||||
|
||||
public Color getColor(FlowType flowType) {
|
||||
|
@ -227,4 +242,12 @@ public class FunctionGraphOptions extends VisualGraphOptions {
|
|||
|
||||
return Color.BLACK;
|
||||
}
|
||||
|
||||
public FGLayoutOptions getLayoutOptions(String layoutName) {
|
||||
return layoutOptionsByName.get(layoutName);
|
||||
}
|
||||
|
||||
public void setLayoutOptions(String layoutName, FGLayoutOptions options) {
|
||||
layoutOptionsByName.put(layoutName, options);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -53,7 +53,6 @@ import ghidra.app.plugin.core.clipboard.ClipboardPlugin;
|
|||
import ghidra.app.plugin.core.codebrowser.CodeBrowserPlugin;
|
||||
import ghidra.app.plugin.core.functiongraph.graph.*;
|
||||
import ghidra.app.plugin.core.functiongraph.graph.layout.FGLayoutProvider;
|
||||
import ghidra.app.plugin.core.functiongraph.graph.layout.TestFGLayoutProvider;
|
||||
import ghidra.app.plugin.core.functiongraph.graph.vertex.*;
|
||||
import ghidra.app.plugin.core.functiongraph.mvc.*;
|
||||
import ghidra.app.services.*;
|
||||
|
@ -75,7 +74,6 @@ import ghidra.program.util.ProgramSelection;
|
|||
import ghidra.test.*;
|
||||
import ghidra.util.Msg;
|
||||
import ghidra.util.task.RunManager;
|
||||
import util.CollectionUtils;
|
||||
|
||||
public abstract class AbstractFunctionGraphTest extends AbstractGhidraHeadedIntegrationTest {
|
||||
|
||||
|
@ -558,9 +556,6 @@ public abstract class AbstractFunctionGraphTest extends AbstractGhidraHeadedInte
|
|||
|
||||
graphProvider = waitForComponentProvider(FGProvider.class);
|
||||
assertNotNull("Graph not shown", graphProvider);
|
||||
|
||||
FGActionManager actionManager = graphProvider.getActionManager();
|
||||
actionManager.setLayoutFinder(() -> CollectionUtils.asSet(new TestFGLayoutProvider()));
|
||||
}
|
||||
|
||||
protected ProgramSelection makeSingleVertexSelectionInCodeBrowser() {
|
||||
|
|
|
@ -25,6 +25,7 @@ import javax.swing.Icon;
|
|||
import ghidra.app.plugin.core.functiongraph.graph.FGEdge;
|
||||
import ghidra.app.plugin.core.functiongraph.graph.FunctionGraph;
|
||||
import ghidra.app.plugin.core.functiongraph.graph.vertex.FGVertex;
|
||||
import ghidra.app.plugin.core.functiongraph.graph.vertex.GroupedFunctionGraphVertex;
|
||||
import ghidra.graph.VisualGraph;
|
||||
import ghidra.graph.viewer.layout.*;
|
||||
import ghidra.graph.viewer.vertex.VisualGraphVertexShapeTransformer;
|
||||
|
@ -37,13 +38,14 @@ import resources.Icons;
|
|||
/**
|
||||
* A simple layout that is used during testing
|
||||
*/
|
||||
public class TestFGLayoutProvider implements FGLayoutProvider {
|
||||
public class TestFGLayoutProvider extends FGLayoutProvider {
|
||||
|
||||
private static final String NAME = "Test Layout";
|
||||
private static final int VERTEX_TO_EDGE_ARTICULATION_OFFSET = 20;
|
||||
|
||||
@Override
|
||||
public String getLayoutName() {
|
||||
return "Test Layout";
|
||||
return NAME;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -65,7 +67,7 @@ public class TestFGLayoutProvider implements FGLayoutProvider {
|
|||
private class TestFGLayout extends AbstractFGLayout {
|
||||
|
||||
protected TestFGLayout(FunctionGraph graph) {
|
||||
super(graph);
|
||||
super(graph, NAME);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -224,7 +226,9 @@ public class TestFGLayoutProvider implements FGLayoutProvider {
|
|||
treeify(g, left, nodesByVertices);
|
||||
break;
|
||||
default:
|
||||
Msg.debug(this, "\n\n\tMore than 2 edges????: " + parent);
|
||||
if (!(parent.v instanceof GroupedFunctionGraphVertex)) {
|
||||
Msg.debug(this, "\n\n\tMore than 2 edges????: " + parent);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -357,5 +361,16 @@ public class TestFGLayoutProvider implements FGLayoutProvider {
|
|||
Node(FGVertex v) {
|
||||
this.v = v;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
//@formatter:off
|
||||
return "{\n" +
|
||||
"\tv: " + v + ",\n" +
|
||||
"\tleft: " + left + ",\n" +
|
||||
"\tright: " + right + "\n" +
|
||||
"}";
|
||||
//@formatter:on
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue