/** * @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; }
/** * @param currentElement * @param context * @param cellOfElement */ private void prelayoutSuccessors( BPMNElement currentElement, GridContext context, Cell<BPMNElement> cellOfElement) { // preLayout following Elements Cell<BPMNElement> baseCell = cellOfElement.after(); Cell<BPMNElement> topCell = baseCell; List<LayoutingElement> followingElements = currentElement.getFollowingElements(); if (BPMNType.isAActivity(currentElement.getType())) { // special case for docked events List<BPMNElement> dockedEventFollowers = new LinkedList<BPMNElement>(); for (LayoutingElement el : currentElement.getOutgoingLinks()) { BPMNElement element = (BPMNElement) el; if (element.isADockedIntermediateEvent()) { for (LayoutingElement follower : element.getFollowingElements()) { dockedEventFollowers.add((BPMNElement) follower); } } } // to avoid crossing edges if there is more than one // docked event Collections.reverse(dockedEventFollowers); // put them under the task Cell<BPMNElement> insertCell = baseCell; for (BPMNElement dockedEventFollower : dockedEventFollowers) { Cell<BPMNElement> oldCell = context.grid.getCellOfItem(dockedEventFollower); if (oldCell != null) { if (oldCell.getValue() == dockedEventFollower) { continue; // Bug-Workaround: Don't prelayout // layouted elements; } } insertCell.getParent().insertRowBeneath(); insertCell = insertCell.beneath(); context.grid.setCellOfItem(dockedEventFollower, insertCell); // prelayout } // remove them from the following processing followingElements.removeAll(dockedEventFollowers); } // heuristic for text- & data-objects: put them to the top List<BPMNElement> textAnnotations = new LinkedList<BPMNElement>(); List<BPMNElement> dataObjects = new LinkedList<BPMNElement>(); for (LayoutingElement el : followingElements) { BPMNElement e = (BPMNElement) el; if (e.getType().equals(BPMNType.TextAnnotation)) { textAnnotations.add(e); } else if (e.getType().equals(BPMNType.DataObject)) { dataObjects.add(e); } } followingElements.removeAll(textAnnotations); followingElements.removeAll(dataObjects); // add them at the front followingElements.addAll(0, dataObjects); followingElements.addAll(0, textAnnotations); // heuristic for direct connection to join BPMNElement directJoin = null; for (LayoutingElement possibleJoin : followingElements) { if (possibleJoin.isJoin()) { directJoin = (BPMNElement) possibleJoin; } } if (directJoin != null) { // put in the middle followingElements.remove(directJoin); int position = (followingElements.size() / 2); followingElements.add(position, directJoin); } // normal preLayout following Elements int follow = 0; for (LayoutingElement newElem : followingElements) { if (newElem.getParent() == currentElement.getParent()) { follow++; } } for (int i = 0; i < follow / 2; i++) { topCell.getParent().insertRowAbove(); baseCell.getParent().insertRowBeneath(); topCell = topCell.above(); } for (LayoutingElement newElem : followingElements) { if (newElem.getParent() != currentElement.getParent()) { continue; } context.grid.setCellOfItem((BPMNElement) newElem, topCell); // prelayout topCell = topCell.beneath(); if (topCell == baseCell && follow % 2 == 0) { // skip baseCell if an even amount of elements is // following topCell = topCell.beneath(); } } }