blob: 79b421208b5143e8f385d1e1e707ea265f4f37e3 [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 java.util.Iterator;
import org.eclipse.draw2d.geometry.Dimension;
import org.eclipse.draw2d.geometry.Insets;
/**
* A node in a DirectedGraph. A node has 0 or more incoming and outgoing
* {@link Edge}s. A node is given a width and height by the client. When a
* layout places the node in the graph, it will determine the node's x and y
* location. It may also modify the node's height.
*
* A node represents both the <EM>input</EM> and the <EM>output</EM> for a
* layout algorithm. The following fields are used as input to a graph layout:
* <UL>
* <LI>{@link #width} - the node's width.
* <LI>{@link #height} - the node's height.
* <LI>{@link #outgoing} - the node's outgoing edges.
* <LI>{@link #incoming} - the node's incoming edges.
* <LI>padding - the amount of space to be left around the outside of the node.
* <LI>{@link #incomingOffset} - the default attachment point for incoming
* edges.
* <LI>{@link #outgoingOffset} - the default attachment point for outgoing
* edges.
* <LI>parent - the parent subgraph containing this node.
* </UL>
* <P>
* The following fields are calculated by a graph layout and comprise the
* <EM>output</EM>:
* <UL>
* <LI>{@link #x} - the node's x location
* <LI>{@link #y} - the node's y location
* <LI>{@link #height} - the node's height may be stretched to match the height
* of other nodes
* </UL>
*
* @author Randy Hudson
* @since 2.1.2
*/
public class Node {
Node left, right;
Object workingData[] = new Object[3];
int workingInts[] = new int[4];
/**
* Clients may use this field to mark the Node with an arbitrary data
* object.
*/
public Object data;
// used by various graph visitors
boolean flag;
/**
* The height of this node. This value should be set prior to laying out the
* directed graph. Depending on the layout rules, a node's height may be
* expanded to match the height of other nodes around it.
*/
public int height = 40;
/**
* @deprecated use {@link #setRowConstraint(int)} and
* {@link #getRowConstraint()}
*/
public int rowOrder = -1;
/**
* The edges for which this node is the target.
*/
public EdgeList incoming = new EdgeList();
/**
* The default attachment point for incoming edges. <code>-1</code>
* indicates that the node's horizontal center should be used.
*/
public int incomingOffset = -1;
// A non-decreasing number given to consecutive nodes in a Rank.
int index;
// Used in Compound graphs to quickly determine whether a node is inside a
// subgraph.
int nestingIndex = -1;
/**
* The edges for which this node is the source.
*/
public EdgeList outgoing = new EdgeList();
Insets padding;
private Subgraph parent;
int rank;
/**
* @deprecated for internal use only
*/
public double sortValue;
/**
* The node's outgoing offset attachment point.
*/
public int outgoingOffset = -1;
/**
* The node's width. The default value is 50.
*/
public int width = 50;
/**
* The node's x coordinate.
*/
public int x;
/**
* The node's y coordinate.
*/
public int y;
/**
* Constructs a new node.
*/
public Node() {
}
/**
* Constructs a node with the given data object
*
* @param data
* an arbitrary data object
*/
public Node(Object data) {
this(data, null);
}
/**
* Constructs a node inside the given subgraph.
*
* @param parent
* the parent subgraph
*/
public Node(Subgraph parent) {
this(null, parent);
}
/**
* Constructs a node with the given data object and parent subgraph. This
* node is added to the set of members for the parent subgraph
*
* @param data
* an arbitrary data object
* @param parent
* the parent subgraph or <code>null</code>
*/
public Node(Object data, Subgraph parent) {
this.data = data;
this.parent = parent;
if (parent != null)
parent.addMember(this);
}
/**
* Returns the incoming attachment point. This is the distance from the left
* edge to the default incoming attachment point for edges. Each incoming
* edge may have it's own attachment setting which takes priority over this
* default one.
*
* @return the incoming offset
*/
public int getOffsetIncoming() {
if (incomingOffset == -1)
return width / 2;
return incomingOffset;
}
/**
* Returns the outgoing attachment point. This is the distance from the left
* edge to the default outgoing attachment point for edges. Each outgoing
* edge may have it's own attachment setting which takes priority over this
* default one.
*
* @return the outgoing offset
*/
public int getOffsetOutgoing() {
if (outgoingOffset == -1)
return width / 2;
return outgoingOffset;
}
/**
* Returns the padding for this node or <code>null</code> if the default
* padding for the graph should be used.
*
* @return the padding or <code>null</code>
*/
public Insets getPadding() {
return padding;
}
/**
* Returns the parent Subgraph or <code>null</code> if there is no parent.
* Subgraphs are only for use in {@link CompoundDirectedGraphLayout}.
*
* @return the parent or <code>null</code>
*/
public Subgraph getParent() {
return parent;
}
/**
* For internal use only. Returns <code>true</code> if the given node is
* equal to this node. This method is implemented for consitency with
* Subgraph.
*
* @param node
* the node in question
* @return <code>true</code> if nested
*/
boolean isNested(Node node) {
return node == this;
}
/**
* Sets the padding. <code>null</code> indicates that the default padding
* should be used.
*
* @param padding
* an insets or <code>null</code>
*/
public void setPadding(Insets padding) {
this.padding = padding;
}
/**
* Sets the parent subgraph. This method should not be called directly. The
* constructor will set the parent accordingly.
*
* @param parent
* the parent
*/
public void setParent(Subgraph parent) {
this.parent = parent;
}
/**
* Sets the row sorting constraint for this node. By default, a node's
* constraint is <code>-1</code>. If two nodes have different values both >=
* 0, the node with the smaller constraint will be placed to the left of the
* other node. In all other cases no relative placement is guaranteed.
*
* @param value
* the row constraint
* @since 3.2
*/
public void setRowConstraint(int value) {
this.rowOrder = value;
}
/**
* Returns the row constraint for this node.
*
* @return the row constraint
* @since 3.2
*/
public int getRowConstraint() {
return rowOrder;
}
/**
* Sets the size of this node to the given dimension.
*
* @param size
* the new size
* @since 3.2
*/
public void setSize(Dimension size) {
width = size.width;
height = size.height;
}
/**
* @see Object#toString()
*/
public String toString() {
return "N(" + data + ")"; //$NON-NLS-1$ //$NON-NLS-2$
}
Iterator iteratorNeighbors() {
return new Iterator() {
int offset;
EdgeList list = outgoing;
public Object next() {
Edge edge = list.getEdge(offset++);
if (offset < list.size())
return edge.opposite(Node.this);
if (list == outgoing) {
list = incoming;
offset = 0;
} else
list = null;
return edge.opposite(Node.this);
}
public boolean hasNext() {
if (list == null)
return false;
if (offset < list.size())
return true;
if (list == outgoing) {
list = incoming;
offset = 0;
}
return offset < list.size();
}
public void remove() {
throw new RuntimeException("Remove not supported"); //$NON-NLS-1$
}
};
}
/**
* Returns a reference to a node located left from this one
*
* @return <code>Node</code> on the left from this one
* @since 3.4
*/
public Node getLeft() {
return left;
}
/**
* Returns a reference to a node located right from this one
*
* @return <code>Node</code> on the right from this one
* @since 3.4
*/
public Node getRight() {
return right;
}
}