private void prepareLanes(BPMNElement lane, int level) { maxLaneDepth = Math.max(maxLaneDepth, level); List<BPMNElement> childs = new ArrayList<BPMNElement>(); BPMNElement aChild = null; for (LayoutingElement c : diagram.getChildElementsOf(lane)) { BPMNElement child = (BPMNElement) c; if (BPMNType.isASwimlane(child.getType())) { prepareLanes(child, level + 1); childs.add(child); } aChild = child; } // Create Grid for lane (= // aChild.getParent()) if (aChild != null) { getContextByElement(aChild); } else { // create empty grid for empty lanes // to prevent nullpointer-exception GridContext result = new GridContext(); result.grid = new Grid<BPMNElement>(); result.startCell = result.grid.getFirstRow().getFirstCell(); superGrid.add(result.grid); parent2Context.put(lane, result); } lane2LaneChilds.put(lane, childs); }
/** * @param lane * @param relY * @param level * @return height of lane */ private double placeLane(BPMNElement lane, double relY, int level) { List<BPMNElement> childs = lane2LaneChilds.get(lane); double height = 0; for (BPMNElement child : childs) { height += placeLane(child, height, level + 1); } int width = poolWidth - level * LANE_HEAD_WIDTH; Grid<BPMNElement> myGrid = parent2Context.get(lane).grid; int firstRow = superGrid.findRow(myGrid.getFirstRow()); int lastRow = superGrid.findRow(myGrid.getLastRow()); for (int i = firstRow; i <= lastRow; i++) { height += heightOfRow[i]; } double minHeight = lane.getGeometry().getHeight(); if (level == 0) { minHeight += CELL_MARGIN / 2; } double diff = minHeight - height; if (diff > 1.0) { firstRow = superGrid.findRow(findFirstGridOfPool(lane).getFirstRow()); double toAdd = diff / (lastRow - firstRow + 1.0); for (int i = firstRow; i <= lastRow; i++) { heightOfRow[i] += toAdd; } // Redo placement return placeLane(lane, relY, level); } if (level == 0) { // pool with magin lane.setGeometry( new LayoutingBoundsImpl( CELL_MARGIN, relY + (CELL_MARGIN / 4), width, height - (CELL_MARGIN / 2))); } else { // lane without margin lane.setGeometry(new LayoutingBoundsImpl(CELL_MARGIN, relY, width, height)); } lane.updateDataModel(); return height; }
/** @param grids */ private void calcGeometry(SuperGrid<BPMNElement> grids) { grids.pack(); heightOfRow = new double[grids.getHeight()]; widthOfColumn = new double[grids.getWidth()]; // initialize with standard values Arrays.fill(heightOfRow, CELL_HEIGHT); Arrays.fill(widthOfColumn, CELL_WIDTH); // find biggest int row = 0; int column = 0; for (Row<BPMNElement> r : grids) { column = 0; for (Cell<BPMNElement> c : r) { if (c.isFilled()) { BPMNElement elem = c.getValue(); LayoutingBounds geom = elem.getGeometry(); widthOfColumn[column] = Math.max(widthOfColumn[column], geom.getWidth() + CELL_MARGIN); heightOfRow[row] = Math.max(heightOfRow[row], geom.getHeight() + CELL_MARGIN); } column++; } row++; } // calc width / height widthOfSuperGrid = 0; for (double columnWidth : widthOfColumn) { widthOfSuperGrid += columnWidth; } heightOfSuperGrid = 0; for (double rowHeight : heightOfRow) { heightOfSuperGrid += rowHeight; } poolWidth = maxLaneDepth * LANE_HEAD_WIDTH; poolWidth += widthOfSuperGrid; }
private GridContext getContextByElement(BPMNElement el) { BPMNElement elParent = null; if (el != null) { elParent = (BPMNElement) el.getParent(); } GridContext result = parent2Context.get(elParent); if (result == null) { result = new GridContext(); result.grid = new Grid<BPMNElement>(); result.startCell = result.grid.getFirstRow().getFirstCell(); superGrid.add(result.grid); parent2Context.put(elParent, result); } return result; }
/** * @param currentElement * @param precedingElements * @param context * @return cellOfElement */ private Cell<BPMNElement> placeElement( BPMNElement currentElement, List<LayoutingElement> precedingElements, GridContext context) { Cell<BPMNElement> newCell; if (precedingElements.isEmpty()) { // StartEvents context.startCell.setValue(currentElement); newCell = context.startCell; context.startCell = context.startCell.beneath(); } else { Cell<BPMNElement> leftCell; newCell = context.grid.getCellOfItem(currentElement); // not // null // if // join if (currentElement.isJoin()) { Point tmp; boolean splitFound = false; BPMNElement split = (BPMNElement) currentElement.prevSplit(); if (split != null) { // get all close splits Queue<BPMNElement> splits = new PriorityQueue<BPMNElement>( precedingElements.size() / 2, // should be a // good rule of // thumb new BackwardDistanceComperator(currentElement)); splits.add(split); for (LayoutingElement elem : precedingElements) { split = (BPMNElement) elem.prevSplit(); if (split != null && !splits.contains(split)) { splits.add(split); } } split = null; // get split with most connections int maxCon = 0; for (BPMNElement target : splits) { if (target == currentElement) { // beeing my own splits only makes trouble continue; } else if (target.getParent() != currentElement.getParent()) { continue; } int curCon = 0; for (LayoutingElement elem : precedingElements) { if (elem.backwardDistanceTo(target) < Integer.MAX_VALUE) { curCon++; } } if (curCon > maxCon) { maxCon = curCon; split = target; } } splitFound = split != null; } int x = 0; int yAcc = 0; int yCnt = 0; for (LayoutingElement el : precedingElements) { BPMNElement elem = (BPMNElement) el; tmp = context.grid.find(context.grid.getCellOfItem(elem)); if (tmp == null) { Grid<BPMNElement> preGrid = getContextByElement(elem).grid; tmp = preGrid.find(preGrid.getCellOfItem(elem)); if (tmp == null) { tmp = new Point(0, 0); } } else { yAcc += tmp.y; yCnt++; } x = Math.max(x, tmp.x); } if (splitFound) { leftCell = context.grid.getCellOfItem(split).getParent().get(x); // set path to split unpackable for (Cell<BPMNElement> cCell = leftCell; cCell.getValue() != split; cCell = cCell.getPrevCell()) { cCell.setPackable(false); } } else { if (yCnt == 0) { leftCell = context.grid.getFirstRow().above().get(x); } else { leftCell = context.grid.get(yAcc / yCnt).get(x); } } if (newCell != null && newCell.getValue() == currentElement) { newCell.setValue(null); } newCell = leftCell.after(); // set all incoming pathes unpackable for (LayoutingElement e : precedingElements) { BPMNElement el = (BPMNElement) e; Cell<BPMNElement> target = context.grid.getCellOfItem(el); if (target == null) { // don't set unpackable in other grids (other edge // layout) continue; } Cell<BPMNElement> start = target.getParent().get(x + 1); for (Cell<BPMNElement> cCell = start; cCell != target; cCell = cCell.getPrevCell()) { cCell.setPackable(false); } } // if not prelayouted } else if (newCell == null) { BPMNElement preElem = (BPMNElement) precedingElements.get(0); leftCell = context.grid.getCellOfItem(preElem); if (leftCell == null) { Grid<BPMNElement> preGrid = getContextByElement(preElem).grid; Cell<BPMNElement> preCell = preGrid.getCellOfItem(preElem); if (preCell == null) { System.err.println("Cannot find Cell for " + preElem); } List<Grid<BPMNElement>> grids = superGrid.getGrids(); Row<BPMNElement> newRow = null; if (grids.indexOf(preGrid) < grids.indexOf(context.grid)) { newRow = context.grid.addFirstRow(); } else { newRow = context.grid.addLastRow(); } leftCell = newRow.get(Math.max(0, preCell.getParent().find(preCell))); } newCell = leftCell.after(); } if (newCell.isFilled() && !newCell.getValue().equals(currentElement)) { newCell.getParent().insertRowBeneath(); newCell = newCell.beneath(); } newCell.setValue(currentElement); } return newCell; }
public void doLayout() { superGrid = new SuperGrid<BPMNElement>(); parent2Context.clear(); lane2LaneChilds.clear(); maxLaneDepth = 0; if (parent == null) { for (LayoutingElement pool : diagram.getElementsOfType(BPMNType.Pool)) { prepareLanes((BPMNElement) pool, 1); } } layoutElements(); if (parent == null) { // set collapsed pools List<LayoutingElement> collapsedPools = this.diagram.getElementsOfType(BPMNType.CollapsedPool); Grid<BPMNElement> cpGrid = new Grid<BPMNElement>(); superGrid.add(0, cpGrid); for (LayoutingElement collapsedPool : collapsedPools) { // make them small to not disturb finding the biggest ones in // each row / column collapsedPool.setGeometry(new LayoutingBoundsImpl(0, 0, 0, COLLAPSED_POOL_HEIGHT)); for (Cell<BPMNElement> insertCell : cpGrid.addLastRow()) { insertCell.setValue((BPMNElement) collapsedPool); } } calcGeometry(superGrid); poolWidth = Math.max(poolWidth, COLLAPSED_POOL_MIN_WIDTH); // place Lanes for (LayoutingElement pool : diagram.getElementsOfType(BPMNType.Pool)) { Grid<BPMNElement> firstGrid = findFirstGridOfPool((BPMNElement) pool); int firstGridFirstRowIndex = superGrid.findRow(firstGrid.getFirstRow()); double poolY = 0; for (int i = 0; i < firstGridFirstRowIndex; i++) { poolY += heightOfRow[i]; } placeLane((BPMNElement) pool, poolY, 0); } writeGeometry(superGrid); // set pools to start at x = CELL_MARGIN & correct size for (LayoutingElement collapsedPool : collapsedPools) { collapsedPool.setGeometry( new LayoutingBoundsImpl( CELL_MARGIN, collapsedPool.getGeometry().getY(), poolWidth, COLLAPSED_POOL_HEIGHT)); ((BPMNElement) collapsedPool).updateDataModel(); } // convert Coordinates of Elements in Lanes from absolut to // realitive for (LayoutingElement pool : diagram.getElementsOfType(BPMNType.Pool)) { correctLaneElements((BPMNElement) pool, pool.getGeometry().getY(), 0); } } else { calcGeometry(superGrid); writeGeometry(superGrid); } }