| /****************************************************************************** |
| * Copyright (c) 2008 IBM Corporation and others. |
| * All rights reserved. This program and the accompanying materials |
| * are made available under the terms of the Eclipse Public License v1.0 |
| * which accompanies this distribution, and is available at |
| * http://www.eclipse.org/legal/epl-v10.html |
| * |
| * Contributors: |
| * IBM Corporation - initial API and implementation |
| ****************************************************************************/ |
| |
| package org.eclipse.gmf.runtime.draw2d.ui.graph; |
| |
| import java.util.ArrayList; |
| import java.util.Collections; |
| import java.util.Comparator; |
| import java.util.Iterator; |
| import java.util.List; |
| |
| import org.eclipse.draw2d.PositionConstants; |
| import org.eclipse.draw2d.geometry.Dimension; |
| import org.eclipse.draw2d.geometry.Point; |
| import org.eclipse.draw2d.graph.DirectedGraph; |
| import org.eclipse.draw2d.graph.Node; |
| |
| /** |
| * Performs the pre-routing work such as to route edges from border nodes located on left or right sides of a parent node. |
| * Those edges are assigned <code>startingRoutedPoints</code> and/or <endingRoutedPoints</code> to route edges to the top or |
| * bottom of the parent node rank. |
| * This class can be used to do some pre-routing work for orthogonal edges in the future. |
| * |
| * @author aboyko |
| * @since 2.1 |
| */ |
| class PreRouteEdges { |
| |
| private DirectedGraph g; |
| |
| public PreRouteEdges(DirectedGraph g) { |
| this.g = g; |
| } |
| |
| void preRouteEdges() { |
| for (int i = 0; i < g.nodes.size(); i++) { |
| Node n = g.nodes.getNode(i); |
| if (n instanceof ConstantSizeNode) { |
| preRouteEdgesFromNode((ConstantSizeNode)n); |
| } |
| } |
| } |
| |
| private void preRouteEdgesFromNode(ConstantSizeNode n) { |
| List<BorderNode> leftBorderNodes = new ArrayList<BorderNode>(); |
| List<BorderNode> rightBorderNodes = new ArrayList<BorderNode>(); |
| for (Iterator<BorderNode> itr = n.borderNodes.iterator(); itr.hasNext();) { |
| BorderNode bn = itr.next(); |
| if (bn.position == PositionConstants.EAST) { |
| rightBorderNodes.add(bn); |
| } else if (bn.position == PositionConstants.WEST) { |
| leftBorderNodes.add(bn); |
| } |
| } |
| createRoutingPointsForSideBorderNodes(leftBorderNodes, n, PositionConstants.WEST); |
| createRoutingPointsForSideBorderNodes(rightBorderNodes, n, PositionConstants.EAST); |
| } |
| |
| private void createRoutingPointsForSideBorderNodes(List<BorderNode> nodes, ConstantSizeNode parentNode, int position) { |
| List<ConstrainedEdge> incomingEdges = new ArrayList<ConstrainedEdge>(); |
| List<ConstrainedEdge> outgoingEdges = new ArrayList<ConstrainedEdge>(); |
| int maxBorderItemOutsideWidth = initBorderNodeEdgesLists(nodes, incomingEdges, outgoingEdges, position); |
| |
| int nodePadding = position == PositionConstants.WEST ? g.getPadding(parentNode).left : g.getPadding(parentNode).right; |
| |
| if (nodePadding <= maxBorderItemOutsideWidth) { |
| throw new RuntimeException("Node padding must be greater than the the width of the widest border node"); //$NON-NLS-1$ |
| } |
| |
| if (incomingEdges.isEmpty() || outgoingEdges.isEmpty()) { |
| /* |
| * Border nodes sitting on the side should either have both the incoming |
| * and outgoing edges or no edges at all |
| */ |
| return; |
| } |
| |
| int incomingPadding = (nodePadding - maxBorderItemOutsideWidth) / (incomingEdges.size() + 1); |
| int outgoingPadding = (nodePadding - maxBorderItemOutsideWidth) / (outgoingEdges.size() + 1); |
| // if (incomingEdges.size() >= outgoingEdges.size()) { |
| // incomingPadding = (nodePadding - maxBorderItemOutsideWidth) / (incomingEdges.size() + 1); |
| // outgoingPadding = incomingEdges.size() % outgoingEdges.size() == 0 ? (nodePadding - maxBorderItemOutsideWidth) / (outgoingEdges.size() + 2) |
| // : (nodePadding - maxBorderItemOutsideWidth) / (outgoingEdges.size() + 1); |
| // } else { |
| // outgoingPadding = (nodePadding - maxBorderItemOutsideWidth) / (outgoingEdges.size() + 1); |
| // incomingPadding = outgoingEdges.size() % incomingEdges.size() == 0 ? (nodePadding - maxBorderItemOutsideWidth) / (incomingEdges.size() + 2) |
| // : (nodePadding - maxBorderItemOutsideWidth) / (incomingEdges.size() + 1); |
| // } |
| |
| Collections.sort(incomingEdges, new Comparator<ConstrainedEdge>() { |
| public int compare(ConstrainedEdge e1, ConstrainedEdge e2) { |
| int diff = GraphUtilities.getIncomingEdgeBendpointX(e2, g) - GraphUtilities.getIncomingEdgeBendpointX(e1, g); |
| if (e1.targetConstraint.position == PositionConstants.WEST) { |
| return diff; |
| } else { |
| return -diff; |
| } |
| } |
| }); |
| |
| Collections.sort(outgoingEdges, new Comparator<ConstrainedEdge>() { |
| public int compare(ConstrainedEdge e1, ConstrainedEdge e2) { |
| int diff = GraphUtilities.getOutogingEdgeBendpointX(e2, g) - GraphUtilities.getOutogingEdgeBendpointX(e1, g); |
| if (e1.sourceConstraint.position == PositionConstants.WEST) { |
| return diff; |
| } else { |
| return -diff; |
| } |
| } |
| }); |
| |
| int rankHeight = GraphUtilities.getRankHeightFromNode(parentNode, g); |
| Point incomingStartPt = position == PositionConstants.WEST ? new Point(parentNode.x - maxBorderItemOutsideWidth, parentNode.y) |
| : new Point(parentNode.x + parentNode.width + maxBorderItemOutsideWidth, parentNode.y); |
| Point outgoingStartPt = position == PositionConstants.WEST ? new Point(parentNode.x - maxBorderItemOutsideWidth, parentNode.y + rankHeight) |
| : new Point(parentNode.x + parentNode.width + maxBorderItemOutsideWidth, parentNode.y + parentNode.height); |
| Dimension incomingOffset = position == PositionConstants.WEST ? new Dimension(-incomingPadding, 0) |
| : new Dimension(incomingPadding, 0); |
| Dimension outgoingOffset = position == PositionConstants.WEST ? new Dimension(-outgoingPadding, 0) |
| : new Dimension(outgoingPadding, 0); |
| |
| padBendpointsForEdges(incomingEdges, incomingStartPt, incomingOffset, true); |
| padBendpointsForEdges(outgoingEdges, outgoingStartPt, outgoingOffset, false); |
| |
| } |
| |
| private void padBendpointsForEdges(List<ConstrainedEdge> edges, Point startPoint, Dimension offset, boolean incoming) { |
| Point current = startPoint.getCopy().translate(offset); |
| for (Iterator<ConstrainedEdge> itr = edges.iterator(); itr.hasNext(); current.translate(offset)) { |
| ConstrainedEdge e = itr.next(); |
| if (incoming) { |
| e.endingRoutedPoints.addPoint(current); |
| if (e.targetConstraint.minIncomingPadding > 0 || e.targetConstraint.minOutgoingPadding > 0) { |
| e.endingRoutedPoints.addPoint(current.x, e.end.y); |
| } |
| e.endingRoutedPoints.addPoint(e.end); |
| } else { |
| e.startingRoutedPoints.addPoint(e.start); |
| if (e.sourceConstraint.minIncomingPadding > 0 || e.sourceConstraint.minOutgoingPadding > 0) { |
| e.startingRoutedPoints.addPoint(current.x, e.start.y); |
| } |
| e.startingRoutedPoints.addPoint(current); |
| } |
| } |
| } |
| |
| private int initBorderNodeEdgesLists(List<BorderNode> nodes, List<ConstrainedEdge> incomingEdges, List<ConstrainedEdge> outgoingEdges, int position) { |
| int maxBorderNodeOutsideWidth = 0; |
| for (Iterator<BorderNode> itr = nodes.iterator(); itr.hasNext();) { |
| BorderNode bn = itr.next(); |
| if (bn.position == position) { |
| incomingEdges.addAll(bn.incomingJointEdges.edges); |
| outgoingEdges.addAll(bn.outgoingJointEdges.edges); |
| maxBorderNodeOutsideWidth = Math.max(maxBorderNodeOutsideWidth, (int)(bn.width * bn.getOutsideRatio())); |
| } |
| } |
| return maxBorderNodeOutsideWidth; |
| } |
| |
| |
| |
| } |