Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
2c0ec74
JDK-8314512 IGV: clean up hierarchical layout code
Nov 14, 2024
2f4e3fd
AllSoFar
Nov 14, 2024
bf6b263
Revert "AllSoFar"
Nov 26, 2024
a55fc6a
8314512: IGV: clean up hierarchical layout code
Nov 26, 2024
7bfdeef
Node labels in the CFG view left aligned
Nov 27, 2024
b826587
Fix crash: missing Figure after filter applied
Nov 27, 2024
f01593f
cached
Nov 27, 2024
f045e1d
remove dead code in LineWidget
Nov 27, 2024
7617a53
batch add connectionLayer.addChildren(newWidgets);
Nov 27, 2024
f11f43d
run IGV without asserts
Nov 27, 2024
ffa021d
update Figure height calculation for Slots
Nov 27, 2024
ad4d076
remove executability of igv.sh
Nov 27, 2024
2f1157e
fixed graph objects equality
Nov 28, 2024
c08d99e
revert copyright changes
Nov 28, 2024
648057c
8343705: IGV: Interactive Node Moving in Hierarchical Layout
Nov 28, 2024
b8444a3
Merge branch 'pr/22402' into JDK-8343705
Nov 28, 2024
4f7ca8e
JDK-8345041 IGV: Free Placement Mode in IGV Layout
Nov 28, 2024
6fd1060
Merge branch 'master' into JDK-8345041
tobiasholenstein Nov 29, 2024
9623190
missing import after merge
tobiasholenstein Nov 29, 2024
02c182b
Update InputSlot.java
Nov 29, 2024
1051921
Update OutputSlot.java
Nov 29, 2024
bf081c5
Update Slot.java
Nov 29, 2024
227c320
Update HierarchicalLayoutManager.java
Nov 29, 2024
43fb361
Update DiagramScene.java
Nov 29, 2024
1d79e10
finish merge of master
tobiasholenstein Nov 29, 2024
5b6923d
missing
tobiasholenstein Nov 29, 2024
66ad81f
prevent divison by zero
tobiasholenstein Nov 29, 2024
2847b60
layoutNode.setVertex(vertex) and LayoutNode updateSize()
tobiasholenstein Nov 29, 2024
d1843e6
function comment added for setLinkControlPoints
tobiasholenstein Nov 29, 2024
ce9720d
trailing whitespace
tobiasholenstein Nov 29, 2024
14d2018
make applyForceBasedAdjustment more numerical stable
tobiasholenstein Nov 30, 2024
f8d699a
Update LayoutGraph.java
tobiasholenstein Dec 12, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,11 @@ public void setCutEdges(boolean enable) {
maxLayerLength = enable ? 10 : -1;
}

@Override
public boolean isFreeForm() {
return false;
}

@Override
public void doLayout(LayoutGraph layoutGraph) {
layoutGraph.initializeLayout();
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2008, 2024, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
Expand Down Expand Up @@ -169,7 +169,7 @@ public Collection<LayoutNode> getLayoutNodes() {
* Retrieves a combined list of all nodes in the graph,
* including both layout nodes and dummy nodes.
*
* @return An unmodifiable list containing all nodes in the graph.
* @return An unmodifiable list containing all nodes in the graph
*/
public List<LayoutNode> getAllNodes() {
List<LayoutNode> allNodes = new ArrayList<>();
Expand Down Expand Up @@ -447,6 +447,63 @@ public List<Link> getOutputLinks(Vertex vertex) {
return outputLinks;
}

/**
* Checks if the given predecessorVertex is a direct predecessor of the specified vertex.
*
* @param vertex The vertex to check for predecessors.
* @param predecessorVertex The vertex to verify as a predecessor of the given vertex.
* @return true if predecessorVertex is a direct predecessor of vertex, false otherwise.
*/
public boolean isPredecessorVertex(Vertex vertex, Vertex predecessorVertex) {
for (Port inputPort : inputPorts.getOrDefault(vertex, Collections.emptySet())) {
for (Link inputLink : portLinks.getOrDefault(inputPort, Collections.emptySet())) {
Vertex fromVertex = inputLink.getFrom().getVertex();
if (fromVertex.equals(predecessorVertex)) {
return true;
}
}
}
return false;
}

/**
* Checks if the given successorVertex is a direct successor of the specified vertex.
*
* @param vertex The vertex to check for successors.
* @param successorVertex The vertex to verify as a successor of the given vertex.
* @return true if successorVertex is a direct successor of vertex, false otherwise.
*/
public boolean isSuccessorVertex(Vertex vertex, Vertex successorVertex) {
for (Port outputPort : outputPorts.getOrDefault(vertex, Collections.emptySet())) {
for (Link outputLink : portLinks.getOrDefault(outputPort, Collections.emptySet())) {
Vertex toVertex = outputLink.getTo().getVertex();
if (toVertex.equals(successorVertex)) {
return true;
}
}
}
return false;
}

public List<Vertex> getNeighborVertices(Vertex vertex) {
List<Vertex> neighborVertices = new ArrayList<>();
for (Port inputPort : inputPorts.getOrDefault(vertex, Collections.emptySet())) {
for (Link inputLink : portLinks.getOrDefault(inputPort, Collections.emptySet())) {
Vertex fromVertex = inputLink.getFrom().getVertex();
assert fromVertex != null;
neighborVertices.add(fromVertex);
}
}
for (Port outputPort : outputPorts.getOrDefault(vertex, Collections.emptySet())) {
for (Link outputLink : portLinks.getOrDefault(outputPort, Collections.emptySet())) {
Vertex toVertex = outputLink.getTo().getVertex();
assert toVertex != null;
neighborVertices.add(toVertex);
}
}
return neighborVertices;
}

public List<Link> getAllLinks(Vertex vertex) {
List<Link> allLinks = new ArrayList<>();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,5 +49,7 @@ public interface LayoutMover {
* @param movedVertex The vertex to be moved.
*/
void moveVertex(Vertex movedVertex);

boolean isFreeForm();
}

Original file line number Diff line number Diff line change
Expand Up @@ -107,12 +107,7 @@ public LayoutNode() {
this(null);
}

/**
* Initializes the size and margins of the node.
* If the node represents a real vertex, it uses the vertex's size.
* Dummy nodes use default dimensions.
*/
public void initSize() {
public void updateSize() {
if (vertex == null) {
height = DUMMY_HEIGHT;
width = DUMMY_WIDTH;
Expand All @@ -121,6 +116,15 @@ public void initSize() {
height = size.height;
width = size.width;
}
}

/**
* Initializes the size and margins of the node.
* If the node represents a real vertex, it uses the vertex's size.
* Dummy nodes use default dimensions.
*/
public void initSize() {
updateSize();
topMargin = 0;
bottomMargin = 0;
leftMargin = 0;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ public static class DefaultView {
public static final int CLUSTERED_SEA_OF_NODES = 1;
public static final int CONTROL_FLOW_GRAPH = 2;
public static final int STABLE_SEA_OF_NODES = 3;
public static final int INTERACTIVE_FREE_NODES = 4;
}

public static final String NODE_TEXT = "nodeText";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,7 @@ public class DiagramScene extends ObjectScene implements DiagramViewer, DoubleCl

private final Map<OutputSlot, Set<LineWidget>> outputSlotToLineWidget = new HashMap<>();
private final Map<InputSlot, Set<LineWidget>> inputSlotToLineWidget = new HashMap<>();
private final FreeInteractiveLayoutManager freeInteractiveLayoutManager;
private final HierarchicalStableLayoutManager hierarchicalStableLayoutManager;
private HierarchicalLayoutManager seaLayoutManager;
private LayoutMover layoutMover;
Expand Down Expand Up @@ -511,6 +512,7 @@ public void ancestorResized(HierarchyEvent e) {
}
});

freeInteractiveLayoutManager = new FreeInteractiveLayoutManager();
hierarchicalStableLayoutManager = new HierarchicalStableLayoutManager();
seaLayoutManager = new HierarchicalLayoutManager();

Expand Down Expand Up @@ -643,6 +645,8 @@ public void movementStarted(Widget widget) {
widget.bringToFront();
startLayerY = widget.getLocation().y;
hasMoved = false; // Reset the movement flag
if (layoutMover.isFreeForm()) return;

Set<Figure> selectedFigures = model.getSelectedFigures();
if (selectedFigures.size() == 1) {
Figure selectedFigure = selectedFigures.iterator().next();
Expand Down Expand Up @@ -702,8 +706,12 @@ public void setNewLocation(Widget widget, Point location) {
hasMoved = true; // Mark that a movement occurred

int shiftX = location.x - widget.getLocation().x;
int shiftY = magnetToStartLayerY(widget, location);

int shiftY;
if (layoutMover.isFreeForm()) {
shiftY = location.y - widget.getLocation().y;
} else {
shiftY = magnetToStartLayerY(widget, location);
}
List<Figure> selectedFigures = new ArrayList<>( model.getSelectedFigures());
selectedFigures.sort(Comparator.comparingInt(f -> f.getPosition().x));
for (Figure figure : selectedFigures) {
Expand All @@ -713,12 +721,15 @@ public void setNewLocation(Widget widget, Point location) {
if (inputSlotToLineWidget.containsKey(inputSlot)) {
for (LineWidget lw : inputSlotToLineWidget.get(inputSlot)) {
assert lw != null;
Point toPt = lw.getTo();
Point fromPt = lw.getFrom();
if (toPt != null && fromPt != null) {
int xTo = toPt.x + shiftX;
int yTo = toPt.y + shiftY;
lw.setTo(new Point(xTo, yTo));
Point toPt = lw.getTo();
if (toPt == null || fromPt == null) {
continue;
}
int xTo = toPt.x + shiftX;
int yTo = toPt.y + shiftY;
lw.setTo(new Point(xTo, yTo));
if (!layoutMover.isFreeForm()) {
lw.setFrom(new Point(fromPt.x + shiftX, fromPt.y));
LineWidget pred = lw.getPredecessor();
pred.setTo(new Point(pred.getTo().x + shiftX, pred.getTo().y));
Expand All @@ -735,10 +746,13 @@ public void setNewLocation(Widget widget, Point location) {
assert lw != null;
Point fromPt = lw.getFrom();
Point toPt = lw.getTo();
if (toPt != null && fromPt != null) {
int xFrom = fromPt.x + shiftX;
int yFrom = fromPt.y + shiftY;
lw.setFrom(new Point(xFrom, yFrom));
if (toPt == null || fromPt == null) {
continue;
}
int xFrom = fromPt.x + shiftX;
int yFrom = fromPt.y + shiftY;
lw.setFrom(new Point(xFrom, yFrom));
if (!layoutMover.isFreeForm()) {
lw.setTo(new Point(toPt.x + shiftX, toPt.y));
for (LineWidget succ : lw.getSuccessors()) {
succ.setFrom(new Point(succ.getFrom().x + shiftX, succ.getFrom().y));
Expand All @@ -753,10 +767,12 @@ public void setNewLocation(Widget widget, Point location) {
ActionFactory.createDefaultMoveProvider().setNewLocation(fw, newLocation);
}

FigureWidget fw = getWidget(selectedFigures.iterator().next());
pointerWidget.setVisible(true);
Point newLocation = new Point(fw.getLocation().x + shiftX -3, fw.getLocation().y + shiftY);
ActionFactory.createDefaultMoveProvider().setNewLocation(pointerWidget, newLocation);
if (selectedFigures.size() == 1 && !layoutMover.isFreeForm()) {
FigureWidget fw = getWidget(selectedFigures.iterator().next());
pointerWidget.setVisible(true);
Point newLocation = new Point(fw.getLocation().x + shiftX -3, fw.getLocation().y + shiftY);
ActionFactory.createDefaultMoveProvider().setNewLocation(pointerWidget, newLocation);
}
connectionLayer.revalidate();
connectionLayer.repaint();
}
Expand Down Expand Up @@ -834,7 +850,9 @@ private void relayout() {

Set<Figure> visibleFigures = getVisibleFigures();
Set<Connection> visibleConnections = getVisibleConnections();
if (getModel().getShowStableSea()) {
if (getModel().getShowFreeInteractive()) {
doFreeInteractiveLayout(visibleFigures, visibleConnections);
} else if (getModel().getShowStableSea()) {
doStableSeaLayout(visibleFigures, visibleConnections);
} else if (getModel().getShowSea()) {
doSeaLayout(visibleFigures, visibleConnections);
Expand Down Expand Up @@ -904,6 +922,12 @@ private boolean isVisibleFigureConnection(FigureConnection figureConnection) {
return w1.isVisible() && w2.isVisible();
}

private void doFreeInteractiveLayout(Set<Figure> visibleFigures, Set<Connection> visibleConnections) {
layoutMover = freeInteractiveLayoutManager;
freeInteractiveLayoutManager.setCutEdges(model.getCutEdges());
freeInteractiveLayoutManager.doLayout(new LayoutGraph(visibleConnections, visibleFigures));
}

private void doStableSeaLayout(Set<Figure> visibleFigures, Set<Connection> visibleConnections) {
layoutMover = null;
boolean enable = model.getCutEdges();
Expand Down Expand Up @@ -1108,6 +1132,52 @@ private void processOutputSlot(OutputSlot outputSlot, List<FigureConnection> con
}
}

private void processFreeForm(OutputSlot outputSlot, List<FigureConnection> connections) {
for (FigureConnection connection : connections) {
if (isVisibleFigureConnection(connection)) {
boolean isBold = false;
boolean isDashed = true;
boolean isVisible = true;
if (connection.getStyle() == Connection.ConnectionStyle.BOLD) {
isBold = true;
} else if (connection.getStyle() == Connection.ConnectionStyle.INVISIBLE) {
isVisible = false;
}
if (connection.getStyle() != Connection.ConnectionStyle.DASHED) {
isDashed = false;
}


List<Point> controlPoints = connection.getControlPoints();
if (controlPoints.size() <= 2) continue;
Point firstPoint = controlPoints.get(0); // First point
Point lastPoint = controlPoints.get(controlPoints.size() - 1); // Last point
List<FigureConnection> connectionList = new ArrayList<>(Collections.singleton(connection));
LineWidget line = new LineWidget(this, outputSlot, connectionList, firstPoint, lastPoint, null, isBold, isDashed);
line.setFromControlYOffset(50);
line.setToControlYOffset(-50);
line.setVisible(isVisible);
connectionLayer.addChild(line);

addObject(new ConnectionSet(connectionList), line);
line.getActions().addAction(hoverAction);

if (outputSlotToLineWidget.containsKey(outputSlot)) {
outputSlotToLineWidget.get(outputSlot).add(line);
} else {
outputSlotToLineWidget.put(outputSlot, new HashSet<>(Collections.singleton(line)));
}

InputSlot inputSlot = connection.getInputSlot();
if (inputSlotToLineWidget.containsKey(inputSlot)) {
inputSlotToLineWidget.get(inputSlot).add(line);
} else {
inputSlotToLineWidget.put(inputSlot, new HashSet<>(Collections.singleton(line)));
}
}
}
}

private void processBlockConnection(BlockConnection blockConnection) {
boolean isDashed = blockConnection.getStyle() == Connection.ConnectionStyle.DASHED;
boolean isBold = blockConnection.getStyle() == Connection.ConnectionStyle.BOLD;
Expand Down Expand Up @@ -1281,7 +1351,11 @@ private void rebuildConnectionLayer() {
for (Figure figure : getModel().getDiagram().getFigures()) {
for (OutputSlot outputSlot : figure.getOutputSlots()) {
List<FigureConnection> connectionList = new ArrayList<>(outputSlot.getConnections());
processOutputSlot(outputSlot, connectionList, 0, null, null);
if (layoutMover != null && layoutMover.isFreeForm()) {
processFreeForm(outputSlot, connectionList);
} else {
processOutputSlot(outputSlot, connectionList, 0, null, null);
}
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ public class DiagramViewModel extends RangeSliderModel implements ChangedListene
private final ChangedEvent<DiagramViewModel> selectedNodesChangedEvent = new ChangedEvent<>(this);
private final ChangedEvent<DiagramViewModel> hiddenNodesChangedEvent = new ChangedEvent<>(this);
private ChangedListener<InputGraph> titleChangedListener = g -> {};
private boolean showFreeInteractive;
private boolean showStableSea;
private boolean showSea;
private boolean showBlocks;
Expand Down Expand Up @@ -104,6 +105,17 @@ public void setGlobalSelection(boolean enable, boolean fire) {
}
}

public boolean getShowFreeInteractive() {
return showFreeInteractive;
}

public void setShowFreeInteractive(boolean enable) {
showFreeInteractive = enable;
if (enable) {
diagramChangedEvent.fire();
}
}

public boolean getShowStableSea() {
return showStableSea;
}
Expand Down Expand Up @@ -224,6 +236,7 @@ public DiagramViewModel(InputGraph graph) {

globalSelection = GlobalSelectionAction.get(GlobalSelectionAction.class).isSelected();
cutEdges = CutEdgesAction.get(CutEdgesAction.class).isSelected();
showFreeInteractive = Settings.get().getInt(Settings.DEFAULT_VIEW, Settings.DEFAULT_VIEW_DEFAULT) == Settings.DefaultView.INTERACTIVE_FREE_NODES;
showStableSea = Settings.get().getInt(Settings.DEFAULT_VIEW, Settings.DEFAULT_VIEW_DEFAULT) == Settings.DefaultView.STABLE_SEA_OF_NODES;
showSea = Settings.get().getInt(Settings.DEFAULT_VIEW, Settings.DEFAULT_VIEW_DEFAULT) == Settings.DefaultView.SEA_OF_NODES;
showBlocks = Settings.get().getInt(Settings.DEFAULT_VIEW, Settings.DEFAULT_VIEW_DEFAULT) == Settings.DefaultView.CLUSTERED_SEA_OF_NODES;
Expand Down Expand Up @@ -266,7 +279,7 @@ public void setSelectedNodes(Set<Integer> nodes) {
for (String ignored : getPositions()) {
colors.add(Color.black);
}
if (nodes.size() >= 1) {
if (!nodes.isEmpty()) {
for (Integer id : nodes) {
if (id < 0) {
id = -id;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -176,6 +176,11 @@ public void mouseMoved(MouseEvent e) {}
toolBar.addSeparator();
ButtonGroup layoutButtons = new ButtonGroup();

JToggleButton freeInteractiveLayoutButton = new JToggleButton(new EnableFreeLayoutAction(this));
freeInteractiveLayoutButton.setSelected(diagramViewModel.getShowFreeInteractive());
layoutButtons.add(freeInteractiveLayoutButton);
toolBar.add(freeInteractiveLayoutButton);

JToggleButton stableSeaLayoutButton = new JToggleButton(new EnableStableSeaLayoutAction(this));
stableSeaLayoutButton.setSelected(diagramViewModel.getShowStableSea());
layoutButtons.add(stableSeaLayoutButton);
Expand Down
Loading