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); } }