com.mxgraph.layout.mxGraphLayout Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of jgraphx Show documentation
Show all versions of jgraphx Show documentation
JGraphX Swing Component - Java Graph Visualization Library
This is a binary & source redistribution of the original, unmodified JGraphX library originating from:
"https://github.com/jgraph/jgraphx/archive/v3.4.1.3.zip".
The purpose of this redistribution is to make the library available to other Maven projects.
/**
* $Id: mxGraphLayout.java,v 1.28 2012/06/26 10:59:04 david Exp $
* Copyright (c) 2008-2009, JGraph Ltd
*/
package com.mxgraph.layout;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import com.mxgraph.model.mxGeometry;
import com.mxgraph.model.mxIGraphModel;
import com.mxgraph.util.mxConstants;
import com.mxgraph.util.mxPoint;
import com.mxgraph.util.mxRectangle;
import com.mxgraph.view.mxCellState;
import com.mxgraph.view.mxGraph;
import com.mxgraph.view.mxGraph.mxICellVisitor;
import com.mxgraph.view.mxGraphView;
/**
* Abstract bass class for layouts
*/
public abstract class mxGraphLayout implements mxIGraphLayout
{
/**
* Holds the enclosing graph.
*/
protected mxGraph graph;
/**
* The parent cell of the layout, if any
*/
protected Object parent;
/**
* Boolean indicating if the bounding box of the label should be used if
* its available. Default is true.
*/
protected boolean useBoundingBox = true;
/**
* Constructs a new fast organic layout for the specified graph.
*/
public mxGraphLayout(mxGraph graph)
{
this.graph = graph;
}
public void execute(Object parent)
{
this.parent = parent;
}
/* (non-Javadoc)
* @see com.mxgraph.layout.mxIGraphLayout#move(java.lang.Object, double, double)
*/
public void moveCell(Object cell, double x, double y)
{
// TODO: Map the position to a child index for
// the cell to be placed closest to the position
}
/**
* Returns the associated graph.
*/
public mxGraph getGraph()
{
return graph;
}
/**
* Returns the constraint for the given key and cell. This implementation
* always returns the value for the given key in the style of the given
* cell.
*
* @param key Key of the constraint to be returned.
* @param cell Cell whose constraint should be returned.
*/
public Object getConstraint(Object key, Object cell)
{
return getConstraint(key, cell, null, false);
}
/**
* Returns the constraint for the given key and cell. The optional edge and
* source arguments are used to return inbound and outgoing routing-
* constraints for the given edge and vertex. This implementation always
* returns the value for the given key in the style of the given cell.
*
* @param key Key of the constraint to be returned.
* @param cell Cell whose constraint should be returned.
* @param edge Optional cell that represents the connection whose constraint
* should be returned. Default is null.
* @param source Optional boolean that specifies if the connection is incoming
* or outgoing. Default is false.
*/
public Object getConstraint(Object key, Object cell, Object edge,
boolean source)
{
mxCellState state = graph.getView().getState(cell);
Map style = (state != null) ? state.getStyle() : graph
.getCellStyle(cell);
return (style != null) ? style.get(key) : null;
}
/**
* @return the useBoundingBox
*/
public boolean isUseBoundingBox()
{
return useBoundingBox;
}
/**
* @param useBoundingBox the useBoundingBox to set
*/
public void setUseBoundingBox(boolean useBoundingBox)
{
this.useBoundingBox = useBoundingBox;
}
/**
* Returns true if the given vertex may be moved by the layout.
*
* @param vertex Object that represents the vertex to be tested.
* @return Returns true if the vertex can be moved.
*/
public boolean isVertexMovable(Object vertex)
{
return graph.isCellMovable(vertex);
}
/**
* Returns true if the given vertex has no connected edges.
*
* @param vertex Object that represents the vertex to be tested.
* @return Returns true if the vertex should be ignored.
*/
public boolean isVertexIgnored(Object vertex)
{
return !graph.getModel().isVertex(vertex)
|| !graph.isCellVisible(vertex);
}
/**
* Returns true if the given edge has no source or target terminal.
*
* @param edge Object that represents the edge to be tested.
* @return Returns true if the edge should be ignored.
*/
public boolean isEdgeIgnored(Object edge)
{
mxIGraphModel model = graph.getModel();
return !model.isEdge(edge) || !graph.isCellVisible(edge)
|| model.getTerminal(edge, true) == null
|| model.getTerminal(edge, false) == null;
}
/**
* Disables or enables the edge style of the given edge.
*/
public void setEdgeStyleEnabled(Object edge, boolean value)
{
graph.setCellStyles(mxConstants.STYLE_NOEDGESTYLE, (value) ? "0" : "1",
new Object[] { edge });
}
/**
* Disables or enables orthogonal end segments of the given edge
*/
public void setOrthogonalEdge(Object edge, boolean value)
{
graph.setCellStyles(mxConstants.STYLE_ORTHOGONAL, (value) ? "1" : "0",
new Object[] { edge });
}
public mxPoint getParentOffset(Object parent)
{
mxPoint result = new mxPoint();
if (parent != null && parent != this.parent)
{
mxIGraphModel model = graph.getModel();
if (model.isAncestor(this.parent, parent))
{
mxGeometry parentGeo = model.getGeometry(parent);
while (parent != this.parent)
{
result.setX(result.getX() + parentGeo.getX());
result.setY(result.getY() + parentGeo.getY());
parent = model.getParent(parent);;
parentGeo = model.getGeometry(parent);
}
}
}
return result;
}
/**
* Sets the control points of the given edge to the given
* list of mxPoints. Set the points to null to remove all
* existing points for an edge.
*/
public void setEdgePoints(Object edge, List points)
{
mxIGraphModel model = graph.getModel();
mxGeometry geometry = model.getGeometry(edge);
if (geometry == null)
{
geometry = new mxGeometry();
geometry.setRelative(true);
}
else
{
geometry = (mxGeometry) geometry.clone();
}
if (this.parent != null && points != null)
{
Object parent = graph.getModel().getParent(edge);
mxPoint parentOffset = getParentOffset(parent);
for (mxPoint point : points)
{
point.setX(point.getX() - parentOffset.getX());
point.setY(point.getY() - parentOffset.getY());
}
}
geometry.setPoints(points);
model.setGeometry(edge, geometry);
}
/**
* Returns an that defines the bounds of the given cell
* or the bounding box if is true.
*/
public mxRectangle getVertexBounds(Object vertex)
{
mxRectangle geo = graph.getModel().getGeometry(vertex);
// Checks for oversize label bounding box and corrects
// the return value accordingly
if (useBoundingBox)
{
mxCellState state = graph.getView().getState(vertex);
if (state != null)
{
double scale = graph.getView().getScale();
mxRectangle tmp = state.getBoundingBox();
double dx0 = (tmp.getX() - state.getX()) / scale;
double dy0 = (tmp.getY() - state.getY()) / scale;
double dx1 = (tmp.getX() + tmp.getWidth() - state.getX() - state
.getWidth()) / scale;
double dy1 = (tmp.getY() + tmp.getHeight() - state.getY() - state
.getHeight()) / scale;
geo = new mxRectangle(geo.getX() + dx0, geo.getY() + dy0,
geo.getWidth() - dx0 + dx1, geo.getHeight() + -dy0
+ dy1);
}
}
if (this.parent != null)
{
Object parent = graph.getModel().getParent(vertex);
geo = (mxRectangle) geo.clone();
if (parent != null && parent != this.parent)
{
mxPoint parentOffset = getParentOffset(parent);
geo.setX(geo.getX() + parentOffset.getX());
geo.setY(geo.getY() + parentOffset.getY());
}
}
return new mxRectangle(geo);
}
/**
* Sets the new position of the given cell taking into account the size of
* the bounding box if is true. The change is only carried
* out if the new location is not equal to the existing location, otherwise
* the geometry is not replaced with an updated instance. The new or old
* bounds are returned (including overlapping labels).
*
* Parameters:
*
* cell - whose geometry is to be set.
* x - Integer that defines the x-coordinate of the new location.
* y - Integer that defines the y-coordinate of the new location.
*/
public mxRectangle setVertexLocation(Object vertex, double x, double y)
{
mxIGraphModel model = graph.getModel();
mxGeometry geometry = model.getGeometry(vertex);
mxRectangle result = null;
if (geometry != null)
{
result = new mxRectangle(x, y, geometry.getWidth(),
geometry.getHeight());
mxGraphView graphView = graph.getView();
// Checks for oversize labels and offset the result
if (useBoundingBox)
{
mxCellState state = graphView.getState(vertex);
if (state != null)
{
double scale = graph.getView().getScale();
mxRectangle box = state.getBoundingBox();
if (state.getBoundingBox().getX() < state.getX())
{
x += (state.getX() - box.getX()) / scale;
result.setWidth(box.getWidth());
}
if (state.getBoundingBox().getY() < state.getY())
{
y += (state.getY() - box.getY()) / scale;
result.setHeight(box.getHeight());
}
}
}
if (this.parent != null)
{
Object parent = model.getParent(vertex);
if (parent != null && parent != this.parent)
{
mxPoint parentOffset = getParentOffset(parent);
x = x - parentOffset.getX();
y = y - parentOffset.getY();
}
}
if (geometry.getX() != x || geometry.getY() != y)
{
geometry = (mxGeometry) geometry.clone();
geometry.setX(x);
geometry.setY(y);
model.setGeometry(vertex, geometry);
}
}
return result;
}
/**
* Updates the bounds of the given groups to include all children. Call
* this with the groups in parent to child order, top-most group first, eg.
*
* arrangeGroups(graph, mxUtils.sortCells(Arrays.asList(
* new Object[] { v1, v3 }), true).toArray(), 10);
* @param groups the groups to adjust
* @param border the border applied to the adjusted groups
*/
public void arrangeGroups(Object[] groups, int border)
{
graph.getModel().beginUpdate();
try
{
for (int i = groups.length - 1; i >= 0; i--)
{
Object group = groups[i];
Object[] children = graph.getChildVertices(group);
mxRectangle bounds = graph.getBoundingBoxFromGeometry(children);
mxGeometry geometry = graph.getCellGeometry(group);
double left = 0;
double top = 0;
// Adds the size of the title area for swimlanes
if (this.graph.isSwimlane(group))
{
mxRectangle size = graph.getStartSize(group);
left = size.getWidth();
top = size.getHeight();
}
if (bounds != null && geometry != null)
{
geometry = (mxGeometry) geometry.clone();
geometry.setX(geometry.getX() + bounds.getX() - border - left);
geometry.setY(geometry.getY() + bounds.getY() - border - top);
geometry.setWidth(bounds.getWidth() + 2 * border + left);
geometry.setHeight(bounds.getHeight() + 2 * border + top);
graph.getModel().setGeometry(group, geometry);
graph.moveCells(children, border + left - bounds.getX(),
border + top - bounds.getY());
}
}
}
finally
{
graph.getModel().endUpdate();
}
}
}