/** * A childless stran is a "problem" in general because they break the evenness of the tree There * are three types of such strands, extra nodes to the left, extra to the right, or extra in * between parents. This method places those strands in spot. * * @param childlessStrand - the childless node to be laid out. * @param parentLeft - the nearest parent on the left (or <value>null</value> if none such exists) * @param parentRight - the nearest parent on the right (or <value>null</value> if none such * exists) * @param yLoc - the vertical location to lay out the nodes on. */ private void placeChildless( List<GXMoreThanNode> childlessStrand, GXMoreThanNode parentLeft, GXMoreThanNode parentRight, int yLoc) { int startMark = 0; int spacing = (int) (childlessStrand.get(0).getNode().getLayoutEntity().getWidthInLayout() + horSpacing); // There's only a parent on the right if (parentLeft == null && parentRight != null) { startMark = parentRight.getX() - (spacing * childlessStrand.size()); } // there's a parent on the left else if (parentLeft != null) { startMark = parentLeft.getX() + spacing; // there's a parent on the right as well meaning the childless are between two parents // we need to make there's enough room to place them if (parentRight != null) { int endMark = startMark + (spacing * childlessStrand.size()); // if there isn't enough room to place the childless between the parents if (endMark > parentRight.getX()) { // shift everything on the right to the right by the missing amount of space. shiftTreesRightOfMark(parentRight, endMark - parentRight.getX()); } } } // now the room has been assured, place strand. placeStrand(childlessStrand, startMark, yLoc, spacing); }
/** * Returns the right most child of parent * * @param parent * @return the right most child of parent given. */ private GXMoreThanNode getRightMostChild(GXMoreThanNode parent) { GXMoreThanNode rightMost = parent.getChildren().get(0); // run through children for (GXMoreThanNode child : parent.getChildren()) { if (child.getX() < rightMost.getX()) { rightMost = child; } } return rightMost; }
/** * Shifts the trees right of mark node * * @param mark to shift from * @param shift - factor by which to move right by. */ private void shiftTreesRightOfMark(GXMoreThanNode mark, int shift) { mark.setLocation(mark.getX() + shift, mark.getY()); GXMoreThanNode leftMostChild = getRightMostChild(mark); List<GXMoreThanNode> treeRoots = leftMostChild .getRow() .subList(leftMostChild.getRow().indexOf(leftMostChild), leftMostChild.getRow().size()); for (GXMoreThanNode root : treeRoots) { shiftTree(root, shift); } }
/** * Lays out row with respect to it's children. * * @param yLocation - the vertical location to start placing the nodes. * @param row - the row who's nodes we'd like to lay out. */ private void placeRow(List<GXMoreThanNode> row, int yLocation) { List<GXMoreThanNode> childlessStrand = new ArrayList<GXMoreThanNode>(); GXMoreThanNode parentLeft = null; // for each parent in this parent row for (int j = 0; j < row.size(); j++) { GXMoreThanNode parentRight = row.get(j); // if the node has children if (!parentRight.getChildren().isEmpty()) { // place the node in the center above his children int parentX = 0; for (GXMoreThanNode child : parentRight.getChildren()) { parentX += child.getX(); } parentX /= parentRight.getChildren().size(); parentRight.setLocation(parentX, yLocation); // and layout the childless strand if (!childlessStrand.isEmpty()) { placeChildless(childlessStrand, parentLeft, parentRight, yLocation); childlessStrand.clear(); } parentLeft = parentRight; } else { // accumulate the childless nodes childlessStrand.add(parentRight); } } // place childless who are extra on the right. as in did not get taken care of when // the parents were laid out. if (!childlessStrand.isEmpty()) { placeChildless(childlessStrand, parentLeft, null, yLocation); } }
/** * Shifts the given tree by the shift factor given to the right. * * @param root - root of tree to shift * @param shift - factor to shirt by */ private void shiftTree(GXMoreThanNode root, int shift) { root.setLocation(root.getX() + shift, root.getY()); for (GXMoreThanNode child : root.getChildren()) { shiftTree(child, shift); } }