/* * TouchGraph LLC. Apache-Style Software License * * * Copyright (c) 2002 Alexander Shapiro. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by * TouchGraph LLC (http://www.touchgraph.com/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "TouchGraph" or "TouchGraph LLC" must not be used to endorse * or promote products derived from this software without prior written * permission. For written permission, please contact * alex@touchgraph.com * * 5. Products derived from this software may not be called "TouchGraph", * nor may "TouchGraph" appear in their name, without prior written * permission of alex@touchgraph.com. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL TOUCHGRAPH OR ITS CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * */ package com.touchgraph.graphlayout.graphelements; import com.touchgraph.graphlayout.Node; import com.touchgraph.graphlayout.Edge; import com.touchgraph.graphlayout.TGException; import java.util.Collection; import java.util.Vector; import java.util.Hashtable; /** GraphEltSet contains data about the graph's components. Currently * the only components are edges and nodes. * * @author Alexander Shapiro * @author Murray Altheim (added support for IDs) * @version 1.20 */ public class GraphEltSet implements ImmutableGraphEltSet { protected Vector nodes; protected Vector edges; public int nodeCount; // Not really necessary. Keeps count of the nodes added, and does not decrement when // nodes are deleted. Maybe should be kept, but given a more obscure name. /** The Hashtable containing references to the Node IDs of the current graph. */ protected Hashtable nodeIDRegistry = null; // ........... /** Default constructor. */ public GraphEltSet() { nodes = new Vector(); edges = new Vector(); nodeIDRegistry = new Hashtable(); // registry of Node IDs nodeCount = 0; } // Node manipulation ........................... /** Return the Node at int index, null if none are available. */ protected Node nodeAt( int i ) { if ( nodes.size() == 0 ) return null; return (Node)nodes.elementAt(i); } /** Return the number of Nodes in the cumulative Vector. */ public int nodeNum() { return nodes.size(); } /** Registers the Node node via its ID String id. * * @param id the ID of the object. * @param node the Node to be registered. */ //protected void registerNode( String id, Node node ) { // FIXME //} /** Add the Node node to the graph, and * registers the Node via its ID. If no ID exists, no registration occurs. */ public void addNode( Node node ) throws TGException { String id = node.getID(); if ( id != null ) { if ( findNode(id) == null ) { // doesn't already exist nodeIDRegistry.put(id,node); nodes.addElement(node); nodeCount++; } else throw new TGException(TGException.NODE_EXISTS,"node ID '"+id+"' already exists."); } else throw new TGException(TGException.NODE_NO_ID,"node has no ID."); // could be ignored? } /** Returns true if the graph contains the Node node. */ public boolean contains( Node node ) { return nodes.contains(node); } // Edge manipulation ........................... /** Return the Edge at int index, null if none are available. */ protected Edge edgeAt( int index ) { if ( edges.size() == 0 ) return null; return (Edge)edges.elementAt(index); } /** Return the number of Edges in the cumulative Vector. */ public int edgeNum() { return edges.size(); } /** Add the Edge edge to the graph. */ public void addEdge( Edge edge ) { if ( edge == null ) return; if(!contains(edge)) { edges.addElement(edge); edge.from.addEdge(edge); edge.to.addEdge(edge); } } /** Add an Edge from Node from to Node to, * with tension of int tension, returning the Edge. */ public Edge addEdge( Node from, Node to, int tension ) { Edge edge = null; if ( from != null && to != null ) { edge = new Edge(from,to,tension); addEdge(edge); } return edge; } /** Returns true if the graph contains the Edge edge. */ public boolean contains( Edge edge ) { return edges.contains(edge); } /** Return the Node whose ID matches the String id, null if no match is found. */ public Node findNode( String id ) { if ( id == null ) return null; // ignore return (Node)nodeIDRegistry.get(id); } /** Return a Collection of all Nodes whose label matches the String label, * null if no match is found. */ public Collection findNodesByLabel( String label ) { Vector nodelist = new Vector(); for ( int i = 0 ; i < nodeNum() ; i++) { if (nodeAt(i)!=null && nodeAt(i).getLabel().equals(label)) { nodelist.add(nodeAt(i)); } } if ( nodelist.size() == 0 ) return null; else return nodelist; } /** Return an Edge spanning Node from to Node to. */ public Edge findEdge( Node from, Node to ) { for ( int i = 0 ; i < from.edgeNum(); i++ ) { Edge e = from.edgeAt(i); if (e.to == to) return e; } return null; } /** Delete the Edge edge. */ public boolean deleteEdge( Edge edge ) { if ( edge == null ) return false; if (!edges.removeElement(edge)) return false; edge.from.removeEdge(edge); edge.to.removeEdge(edge); return true; } /** Delete the Edges contained within the Vector nodesToDelete. */ public synchronized void deleteEdges( Vector edgesToDelete ) { for (int i=0;ifrom to Node to, * returning true if successful. */ public boolean deleteEdge( Node from, Node to ) { Edge e = findEdge(from,to); if (e!=null) return deleteEdge(e); return false; } /** Delete the Node node, returning true if successful. */ public boolean deleteNode( Node node ) { if ( node == null ) return false; if ( !nodes.removeElement(node) ) return false; String id = node.getID(); if ( id != null ) nodeIDRegistry.remove(id); // remove from registry for ( int i = 0 ; i < node.edgeNum(); i++ ) { Edge e = node.edgeAt(i); if ( e.from == node ) { edges.removeElement(e); // Delete edge not used, because it would change the node's edges e.to.removeEdge(e); // vector which is being iterated on. } else if ( e.to == node ) { edges.removeElement(e); e.from.removeEdge(e); } //No edges are deleted from node. Hopefully garbage collection will pick them up. } return true; } /** Delete the Nodes contained within the Vector nodesToDelete. */ public synchronized void deleteNodes( Vector nodesToDelete ) { for (int i=0;i