package com.mxgraph.view;
import com.mxgraph.model.mxGeometry;
import com.mxgraph.model.mxIGraphModel;
import com.mxgraph.util.mxEvent;
import com.mxgraph.util.mxEventObject;
import com.mxgraph.util.mxEventSource;
import com.mxgraph.util.mxPoint;
public class mxSpaceManager extends mxEventSource
{
/**
* Defines the type of the source or target terminal. The type is a string
* passed to mxCell.is to check if the rule applies to a cell.
*/
protected mxGraph graph;
/**
* Optional string that specifies the value of the attribute to be passed
* to mxCell.is to check if the rule applies to a cell.
*/
protected boolean enabled;
/**
* Optional string that specifies the attributename to be passed to
* mxCell.is to check if the rule applies to a cell.
*/
protected boolean shiftRightwards;
/**
* Optional string that specifies the attributename to be passed to
* mxCell.is to check if the rule applies to a cell.
*/
protected boolean shiftDownwards;
/**
* Optional string that specifies the attributename to be passed to
* mxCell.is to check if the rule applies to a cell.
*/
protected boolean extendParents;
/**
*
*/
protected mxIEventListener resizeHandler = new mxIEventListener()
{
public void invoke(Object source, mxEventObject evt)
{
if (isEnabled())
{
cellsResized((Object[]) evt.getProperty("cells"));
}
}
};
/**
*
*/
public mxSpaceManager(mxGraph graph)
{
setGraph(graph);
}
/**
*
*/
public boolean isCellIgnored(Object cell)
{
return !getGraph().getModel().isVertex(cell);
}
/**
*
*/
public boolean isCellShiftable(Object cell)
{
return getGraph().getModel().isVertex(cell)
&& getGraph().isCellMovable(cell);
}
/**
* @return the enabled
*/
public boolean isEnabled()
{
return enabled;
}
/**
* @param value the enabled to set
*/
public void setEnabled(boolean value)
{
enabled = value;
}
/**
* @return the shiftRightwards
*/
public boolean isShiftRightwards()
{
return shiftRightwards;
}
/**
* @param shiftRightwards the shiftRightwards to set
*/
public void setShiftRightwards(boolean shiftRightwards)
{
this.shiftRightwards = shiftRightwards;
}
/**
* @return the shiftDownwards
*/
public boolean isShiftDownwards()
{
return shiftDownwards;
}
/**
* @param shiftDownwards the shiftDownwards to set
*/
public void setShiftDownwards(boolean shiftDownwards)
{
this.shiftDownwards = shiftDownwards;
}
/**
* @return the extendParents
*/
public boolean isExtendParents()
{
return extendParents;
}
/**
* @param extendParents the extendParents to set
*/
public void setExtendParents(boolean extendParents)
{
this.extendParents = extendParents;
}
/**
* @return the graph
*/
public mxGraph getGraph()
{
return graph;
}
/**
* @param graph the graph to set
*/
public void setGraph(mxGraph graph)
{
if (this.graph != null)
{
this.graph.removeListener(resizeHandler);
}
this.graph = graph;
if (this.graph != null)
{
this.graph.addListener(mxEvent.RESIZE_CELLS, resizeHandler);
this.graph.addListener(mxEvent.FOLD_CELLS, resizeHandler);
}
}
/**
*
*/
protected void cellsResized(Object[] cells)
{
if (cells != null)
{
mxIGraphModel model = getGraph().getModel();
model.beginUpdate();
try
{
for (int i = 0; i < cells.length; i++)
{
if (!isCellIgnored(cells[i]))
{
cellResized(cells[i]);
break;
}
}
}
finally
{
model.endUpdate();
}
}
}
/**
*
*/
protected void cellResized(Object cell)
{
mxGraph graph = getGraph();
mxGraphView view = graph.getView();
mxIGraphModel model = graph.getModel();
mxCellState state = view.getState(cell);
mxCellState pstate = view.getState(model.getParent(cell));
if (state != null && pstate != null)
{
Object[] cells = getCellsToShift(state);
mxGeometry geo = model.getGeometry(cell);
if (cells != null && geo != null)
{
mxPoint tr = view.getTranslate();
double scale = view.getScale();
double x0 = state.getX() - pstate.getOrigin().getX()
- tr.getX() * scale;
double y0 = state.getY() - pstate.getOrigin().getY()
- tr.getY() * scale;
double right = state.getX() + state.getWidth();
double bottom = state.getY() + state.getHeight();
double dx = state.getWidth() - geo.getWidth() * scale + x0
- geo.getX() * scale;
double dy = state.getHeight() - geo.getHeight() * scale + y0
- geo.getY() * scale;
double fx = 1 - geo.getWidth() * scale / state.getWidth();
double fy = 1 - geo.getHeight() * scale / state.getHeight();
model.beginUpdate();
try
{
for (int i = 0; i < cells.length; i++)
{
if (cells[i] != cell && isCellShiftable(cells[i]))
{
shiftCell(cells[i], dx, dy, x0, y0, right, bottom,
fx, fy, isExtendParents()
&& graph.isExtendParent(cells[i]));
}
}
}
finally
{
model.endUpdate();
}
}
}
}
/**
*
*/
protected void shiftCell(Object cell, double dx, double dy, double x0,
double y0, double right, double bottom, double fx, double fy,
boolean extendParent)
{
mxGraph graph = getGraph();
mxCellState state = graph.getView().getState(cell);
if (state != null)
{
mxIGraphModel model = graph.getModel();
mxGeometry geo = model.getGeometry(cell);
if (geo != null)
{
model.beginUpdate();
try
{
if (isShiftRightwards())
{
if (state.getX() >= right)
{
geo = (mxGeometry) geo.clone();
geo.translate(-dx, 0);
}
else
{
double tmpDx = Math.max(0, state.getX() - x0);
geo = (mxGeometry) geo.clone();
geo.translate(-fx * tmpDx, 0);
}
}
if (isShiftDownwards())
{
if (state.getY() >= bottom)
{
geo = (mxGeometry) geo.clone();
geo.translate(0, -dy);
}
else
{
double tmpDy = Math.max(0, state.getY() - y0);
geo = (mxGeometry) geo.clone();
geo.translate(0, -fy * tmpDy);
}
if (geo != model.getGeometry(cell))
{
model.setGeometry(cell, geo);
// Parent size might need to be updated if this
// is seen as part of the resize
if (extendParent)
{
graph.extendParent(cell);
}
}
}
}
finally
{
model.endUpdate();
}
}
}
}
/**
*
*/
protected Object[] getCellsToShift(mxCellState state)
{
mxGraph graph = this.getGraph();
Object parent = graph.getModel().getParent(state.getCell());
boolean down = isShiftDownwards();
boolean right = isShiftRightwards();
return graph.getCellsBeyond(state.getX()
+ ((down) ? 0 : state.getWidth()), state.getY()
+ ((down && right) ? 0 : state.getHeight()), parent, right,
down);
}
/**
*
*/
public void destroy()
{
setGraph(null);
}
}