blob: f0e9632132d117c2abd46f1184aad9cd4945bff1 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2003, 2010 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.draw2d.graph;
import org.eclipse.draw2d.geometry.Point;
import org.eclipse.draw2d.geometry.PointList;
/**
* A directed Edge joining a source and target Node. Edges indicate the
* dependencies between nodes. An Edge provides the information needed to
* perform a graph layout, and it stores the result of the layout in its various
* field. Therefore, it functions both as input and output. The input data
* consists of:
* <UL>
* <LI>{@link #source} - the source Node
* <LI>{@link #target} - the target Node
* <LI>{@link #delta} - the minimum number of rows the edge should span
* <LI>{@link #weight} - a hint indicating this edge's importance
* <LI>{@link #width} - the edge's width
* <LI>{@link #padding} - the amount of space to leave on either side of the
* edge
* <LI>[{@link #offsetSource}] - the edge's attachment point at the source node
* <LI>[{@link #offsetTarget}] - the edge's attachment point at the target node
* </UL>
* <P>
* The output of a layout consists of bending longer edges, and potentially
* inverting edges to remove cycles in the graph. The output consists of:
* <UL>
* <LI>{@link #vNodes} - the virtual nodes (if any) which make up the bendpoints
* <LI>{@link #isFeedback} - <code>true</code> if the edge points backwards
* </UL>
*
* @author hudsonr
* @since 2.1.2
*/
public class Edge {
int cut;
/**
* An arbitrary data field for use by clients.
*/
public Object data;
/**
* The minimum rank separation between the source and target nodes. The
* default value is 1.
*
* @deprecated use accessors instead
*/
public int delta = 1;
/**
* The ending point.
*
* @deprecated use {@link #getPoints()}
*/
public Point end;
boolean flag;
/**
* @deprecated INTERNAL field, use accessor method Indicates an edge was
* inverted during the layout
*/
public boolean isFeedback = false;
/**
* The edge's attachment point at the <em>source</em> node. The default
* value is -1, which indicates that the edge should use the node's default
* {@link Node#getOffsetOutgoing() outgoing} attachment point.
*
* @deprecated use accessors instead
*/
public int offsetSource = -1;
/**
* The edge's attachment point at the <em>target</em> node. The default
* value is -1, which indicates that the edge should use the node's default
* {@link Node#getOffsetIncoming() incoming} attachment point.
*
* @deprecated use accessors instead
*/
public int offsetTarget = -1;
/**
* The minimum amount of space to leave on both the left and right sides of
* the edge.
*
* @deprecated use accessors instead
*/
public int padding = 10;
private PointList points;
/**
* The source Node.
*/
public Node source;
/**
* The starting point.
*
* @deprecated use {@link #getPoints()}
*/
public Point start;
/**
* The target Node.
*/
public Node target;
boolean tree;
/**
* The virtual nodes used to bend edges which go across one or more ranks.
* Each virtual node is just a regular node which occupies some small amount
* of space on a row. It's width is equivalent to the edge's width. Clients
* can use each virtual node's location (x, y, width, and height) as the way
* to position an edge which spans multiple rows.
*/
public NodeList vNodes;
/**
* A hint indicating how straight and short the edge should be relative to
* other edges in the graph. The default value is <code>1</code>.
*/
public int weight = 1;
/**
* @deprecated use accessors instead
*/
public int width = 1;
/**
* Constructs a new edge with the given source and target nodes. All other
* fields will have their default values.
*
* @param source
* the source Node
* @param target
* the target Node
*/
public Edge(Node source, Node target) {
this(null, source, target);
}
/**
* Constructs a new edge with the given source, target, delta, and weight.
*
* @param source
* the source Node
* @param target
* the target Node
* @param delta
* the minimum edge span
* @param weight
* the weight hint
*/
public Edge(Node source, Node target, int delta, int weight) {
this(source, target);
this.delta = delta;
this.weight = weight;
}
/**
* Constructs a new edge with the given data object, source, and target
* node.
*
* @param data
* an arbitrary data object
* @param source
* the source node
* @param target
* the target node
*/
public Edge(Object data, Node source, Node target) {
this.data = data;
this.source = source;
this.target = target;
source.outgoing.add(this);
target.incoming.add(this);
}
/**
* Returns the delta value. The delta is the minimum rank separation for the
* edge's source and target nodes.
*
* @return the delta.
* @since 3.2
*/
public int getDelta() {
return delta;
}
/**
* For internal use only. Returns the index of the {@link Node} (or
* {@link VirtualNode}) on this edge at the given rank. If this edge doesn't
* have a node at the given rank, -1 is returned.
*
* @param rank
* the rank
* @return the edges index at the given rank
*/
int getIndexForRank(int rank) {
if (source.rank == rank)
return source.index;
if (target.rank == rank)
return target.index;
if (vNodes != null)
return vNodes.getNode(rank - source.rank - 1).index;
return -1;
}
/**
* For internal use only. Returns the target node's row minus the source
* node's row.
*
* @return the distance from the source to target ranks
*/
public int getLength() {
return (target.rank - source.rank);
}
public int getPadding() {
return padding;
}
/**
* Returns the path connecting the edge's source and target.
*
* @return a point list
* @since 3.2
*/
public PointList getPoints() {
return points;
}
int getSlack() {
return (target.rank - source.rank) - delta;
}
/**
* Returns the effective source offset for this edge. The effective source
* offset is either the {@link #offsetSource} field, or the source node's
* default outgoing offset if that field's value is -1.
*
* @return the source offset
*/
public int getSourceOffset() {
if (offsetSource != -1)
return offsetSource;
return source.getOffsetOutgoing();
}
/**
* Returns the effective target offset for this edge. The effective target
* offset is either the {@link #offsetTarget} field, or the target node's
* default incoming offset if that field's value is -1.
*
* @return the target offset
*/
public int getTargetOffset() {
if (offsetTarget != -1)
return offsetTarget;
return target.getOffsetIncoming();
}
public int getWidth() {
return width;
}
/**
* Swaps the source and target nodes. If any positional data has been
* calculated, it is inverted as well to reflect the new direction.
*
* @since 2.1.2
*/
public void invert() {
source.outgoing.remove(this);
target.incoming.remove(this);
Node oldTarget = target;
target = source;
source = oldTarget;
int temp = offsetSource;
offsetSource = offsetTarget;
offsetTarget = temp;
target.incoming.add(this);
source.outgoing.add(this);
if (points != null)
points.reverse();
if (vNodes != null) {
NodeList newVNodes = new NodeList();
for (int j = vNodes.size() - 1; j >= 0; j--) {
newVNodes.add(vNodes.getNode(j));
}
vNodes = newVNodes;
}
if (start != null) {
Point pt = start;
start = end;
end = pt;
}
}
/**
* Returns <code>true</code> if the edge was a feedback edge. The layout
* algorithm may invert one or more edges to remove all cycles from the
* input. The set of edges that are inverted are referred to as the
* "feedback" set.
*
* @return <code>true</code> if the edge is feedback
* @since 3.2
*/
public boolean isFeedback() {
return isFeedback;
}
/**
* For internal use only. Returns the node opposite the given node on this
* edge.
*
* @param end
* one end
* @return the other end
*/
public Node opposite(Node end) {
if (source == end)
return target;
return source;
}
/**
* Sets the delta value.
*
* @param delta
* the new delta value
* @since 3.2
*/
public void setDelta(int delta) {
this.delta = delta;
}
/**
* Sets the padding for this edge.
*
* @param padding
* the padding
* @since 3.2
*/
public void setPadding(int padding) {
this.padding = padding;
}
void setPoints(PointList points) {
this.points = points;
start = points.getFirstPoint();
end = points.getLastPoint();
}
/**
* Sets the source node and adds this edge to the new source's outgoing
* edges. If the source node is previously set, removes this edge from the
* old source's outgoing edges.
*
* @param node
* the new source
* @since 3.2
*/
public void setSource(Node node) {
if (source == node)
return;
if (source != null)
source.outgoing.remove(this);
source = node;
if (source != null)
source.outgoing.add(this);
}
public void setSourceOffset(int offset) {
this.offsetSource = offset;
}
/**
* Sets the target node and adds this edge to the new target's incoming
* edges. If the target node is previously set, removes this edge from the
* old target's incoming edges.
*
* @param node
* the new target
* @since 3.2
*/
public void setTarget(Node node) {
if (target == node)
return;
if (target != null)
target.incoming.remove(this);
target = node;
if (target != null)
target.incoming.add(this);
}
public void setTargetOffset(int offset) {
this.offsetTarget = offset;
}
/**
* Sets the width of the edge.
*
* @param width
* the new width
* @since 3.2
*/
public void setWidth(int width) {
this.width = width;
}
}