/******************************************************************************* * Copyright (c) 2003, 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.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; } }