META-INF/MANIFEST.MF
att/grappa/Attribute.java
att/grappa/AttributeHandler.java
att/grappa/CustomRenderer.java
att/grappa/Edge.java
att/grappa/Element.java
att/grappa/ExceptionDisplay.java
att/grappa/Graph.java
att/grappa/GraphEnumeration.java
att/grappa/GraphParserException.java
att/grappa/Grappa.java
att/grappa/GrappaAdapter.java
att/grappa/GrappaBacker.java
att/grappa/GrappaBox.java
att/grappa/GrappaColor.java
att/grappa/GrappaConstants.java
att/grappa/GrappaLine.java
att/grappa/GrappaListener.java
att/grappa/GrappaNexus.java
att/grappa/GrappaPanel.java
att/grappa/GrappaPathIterator.java
att/grappa/GrappaPoint.java
att/grappa/GrappaShape.java
att/grappa/GrappaSize.java
att/grappa/GrappaStyle.java
att/grappa/GrappaSupport.java
att/grappa/GrappaSupportPrintf.java
att/grappa/GrappaSupportRects.java
att/grappa/Lexer.java
att/grappa/Node.java
att/grappa/Parser.cup
att/grappa/Parser.java
att/grappa/Subgraph.java
att/grappa/Symbols.java
att/grappa/Attribute.class
att/grappa/AttributeHandler.class
att/grappa/GrappaConstants.class
att/grappa/CustomRenderer.class
att/grappa/Edge$Enumerator.class
att/grappa/Edge.class
att/grappa/Element.class
att/grappa/Node$Enumerator.class
att/grappa/Node.class
att/grappa/Subgraph$Enumerator.class
att/grappa/Subgraph.class
att/grappa/Graph.class
att/grappa/GrappaNexus.class
att/grappa/GrappaPoint.class
att/grappa/GrappaBox.class
att/grappa/GraphEnumeration.class
att/grappa/GrappaPanel.class
att/grappa/GrappaStyle.class
att/grappa/GrappaBacker.class
att/grappa/GrappaSize.class
att/grappa/GrappaListener.class
att/grappa/ExceptionDisplay$Display.class
att/grappa/ExceptionDisplay$Display$WindowObserver.class
att/grappa/ExceptionDisplay.class
att/grappa/GraphParserException.class
att/grappa/Grappa.class
att/grappa/GrappaAdapter.class
att/grappa/GrappaColor.class
att/grappa/GrappaLine.class
att/grappa/GrappaPathIterator.class
att/grappa/GrappaShape.class
att/grappa/GrappaSupport.class
att/grappa/GrappaSupportPrintf.class
att/grappa/PrintfParser.class
att/grappa/GrappaSupportRects.class
att/grappa/TableField.class
att/grappa/Lexer.class
att/grappa/Parser.class
att/grappa/CUP$Parser$actions.class
att/grappa/Symbols.class
java_cup/runtime/Scanner.java
java_cup/runtime/Symbol.java
java_cup/runtime/lr_parser.java
java_cup/runtime/virtual_parse_stack.java
java_cup/runtime/Symbol.class
java_cup/runtime/lr_parser.class
java_cup/runtime/Scanner.class
java_cup/runtime/virtual_parse_stack.class
Manifest-Version: 1.0
Created-By: 1.4.2_03 (Sun Microsystems Inc.)
att/grappa/Attribute.java
att/grappa/Attribute.java/*
* This software may only be used by you under license from AT&T Corp.
* (“AT&T”). A copy of AT&T’s Source Code Agreement is available at
* AT&T’s Internet website having the URL:
*
* If you received this software without first entering into a license
* with AT&T, you have an infringing copy of this software and cannot use
* it without violating AT&T’s intellectual property rights.
*/
package att.grappa;
import java.util.*;
/**
* A class used for representing attributes associated with the graph elements.
* An attribute consists of a name-value pair and an element type.
* Once an attribute is constructed, the name cannot be changed.
* The element type and the attribute name are used in determining how a
* string representation of an attribute value is to be converted to an
* Object and vice versa. The Element class method setUserAttributeType allows
* users to take advantage of Grappa’s built-in converters or to pass a
* (negative) integer as a conversion indicator to a user-supplied
* AttributeHandler.
*
*
* Grappa String Converters * | |
BOX_TYPE | att.grappa.GrappaBox |
COLOR_TYPE | java.awt.Color |
DIR_TYPE | java.lang.Integer (restricted) |
DOUBLE_TYPE | java.lang.Double |
FONTSTYLE_TYPE | java.lang.Integer (restricted) |
HASHLIST_TYPE | java.lang.Hashtable |
INTEGER_TYPE | java.lang.Integer |
LINE_TYPE | att.grappa.GrappaLine |
POINT_TYPE | att.grappa.GrappaPoint |
SHAPE_TYPE | java.lang.Integer (restricted) |
SIZE_TYPE | att.grappa.GrappaSize |
STRING_TYPE | java.lang.String (default) |
STYLE_TYPE | att.grappa.GrappaStyle |
*
* @see AttributeHandler
* @see Element#setUserAttributeType
*
*
* @version 1.2, 26 May 2005; Copyright 1996 – 2005 by AT&T Corp.
* @author John Mocenigo, Research @ AT&T Labs
*/
public final class Attribute extends java.util.Observable
implements
att.grappa.AttributeHandler,
att.grappa.GrappaConstants
{
// the custom attribute handler
private static AttributeHandler specialHandler = null;
/**
* Set a custom attribute handler for converting a String value
* to an Object and vice versa.
*
* @param newHandler the AttributeHandler to use for conversions
*
* @return the previously set AttributeHandler or null
*
* @see AttributeHandler
*/
public static AttributeHandler setAttributeHandler(AttributeHandler newHandler) {
AttributeHandler oldHandler = specialHandler;
specialHandler = newHandler;
return oldHandler;
}
// attribute name
private String name;
// attribute value as a string
private String stringValue;
// attribute string value converted to an object based on its type
private Object value;
// the element type associated with this attribute (includes system)
private int elementType;
// the attribute type for conversion to/from a string
private int attributeType;
// the hash value of the attribute name
private int nameHash;
/**
* Constructs a new attribute from a name / value pair.
*
* @param elemType the element type with which the attribute is
* or will be associated.
* @param attrName the name of the attribute.
* @param attrValue the value of the attribute.
*
* @see GrappaConstants#NODE
* @see GrappaConstants#EDGE
* @see GrappaConstants#SUBGRAPH
*/
public Attribute(int elemType, String attrName, Object attrValue) {
super();
if(attrName == null) {
throw new IllegalArgumentException(“the name of an Attribute pair cannot be null”);
}
attributeType = attributeType(elemType, attrName);
elementType = elemType;
name = attrName;
nameHash = name.hashCode();
setValue(attrValue);
}
/**
* Constructs a new attribute from an existing one.
*
* @param attr the attribute from which this new one is to be generated
*/
public Attribute(Attribute attr) {
this(attr.getElementType(),attr.getName(),attr.getValue());
}
/**
* Get the element type for this attribute.
*
* @return the element type for this attribute
*
* @see GrappaConstants#NODE
* @see GrappaConstants#EDGE
* @see GrappaConstants#SUBGRAPH
*/
public final int getElementType() {
return elementType;
}
/**
* Get the attribute value type for this attribute.
*
* @return the attribute value type for this attribute.
*/
public final int getAttributeType() {
return attributeType;
}
/**
* Get the name of this attribute.
*
* @return the name of this attribute.
*/
public final String getName() {
return name;
}
/**
* Get the value of this attribute.
*
* @return the value of the attribute.
*/
public final Object getValue() {
if(value == null && stringValue != null) {
value = convertStringValue(elementType,name,stringValue,attributeType);
}
return value;
}
/**
* Get the value of this attribute converted to a String.
*
* @return the value of the attribute as a String.
*/
public final String getStringValue() {
switch(attributeType) {
// put the types here that users might change on their own
// after doing a getValue() so that we always recompute
// the string value when it is requested
case HASHLIST_TYPE:
stringValue = null;
break;
}
if(stringValue == null && value != null) {
stringValue = convertValue(elementType,name,value,attributeType);
}
return stringValue;
}
/**
* Set the value of the attribute. If the value is different than the
* current value, the Observable changed indicator is set.
*
* @param attrValue the new attribute value.
* @return the old attribute value.
*/
public final Object setValue(Object attrValue) {
boolean changed = false;
boolean isString = false;
Object oldValue = null;
if(attrValue != null && attrValue instanceof String) {
isString = true;
oldValue = getStringValue();
attrValue = ((String)attrValue).trim();
} else {
oldValue = getValue();
}
// note: since we have called either getValue() or getStringValue(),
// both value and stringValue are up-to-date
if (attrValue != null) {
if(isString) {
if(changed = (stringValue == null || !attrValue.equals(stringValue))) {
stringValue = (String)attrValue;
value = null;
}
} else {
if(changed = (value == null || !attrValue.equals(value))) {
value = copyValue(elementType, name, attrValue,attributeType);
stringValue = null;
}
}
} else {
if(changed = (value != null)) {
value = null;
stringValue = null;
}
}
if(changed) {
setChanged();
}
return oldValue;
}
/**
* Tests for equality with the given attribute.
*
* @param attr the attribute with which to compare this attribute.
* @return true if the two attributes are equal, false otherwise.
*/
public final boolean equals(Attribute attr) {
if(attr == null) {
return false;
}
if(this == attr) {
return true;
}
if(nameHash != attr.getNameHash() || !attr.getName().equals(name)) {
return false;
}
String attrValue = attr.getStringValue();
if(attrValue == getStringValue()) {
return true;
}
if(attrValue == null) {
return false;
}
// note: since getStringValue() was called, stringValue is up-to-date
return attrValue.equals(stringValue);
}
/**
* Tests for equality of this attribute’s value with the given attribute’s
* value. The attribute names are not compated.
*
* @param attr the attribute with which to compare this attribute.
* @return true if the two attribute values are equal, false otherwise.
*/
public final boolean equalsValue(Attribute attr) {
if(attr == null) {
return false;
}
if(this == attr) {
return true;
}
String attrValue = attr.getStringValue();
if(attrValue == getStringValue()) {
return true;
}
if(attrValue == null) {
return false;
}
// note: since getStringValue() was called, stringValue is up-to-date
return attrValue.equals(stringValue);
}
/**
* Get the hash value for this attributes name.
*
* @return the hash code for the name portion of this attribute
*/
public final int getNameHash() {
return nameHash;
}
/**
* Use to indicate that this object has changed.
* This method is a convenience method that calls the corresponding
* protected method of the Observable class.
*
* @see java.util.Observable#setChanged()
*/
public final void setChanged() {
super.setChanged();
}
/**
* Use to indicate that this object has no longer changed, or that it has
* already notified all of its observers of its most recent change.
* This method is a convenience method that calls the corresponding
* protected method of the Observable class.
*
* @see java.util.Observable#clearChanged()
*/
public final void clearChanged() {
super.clearChanged();
}
/**
* Provide a generic string representation of the attribute.
*/
public String toString() {
return getClass().getName() + “[name=\””+name+”\”,value=\””+getStringValue()+”\”]”;
}
/**
* Convert the supplied value to a string. How to convert the value is
* based on the type, name and attrtype information supplied. Note: this
* method really could be declared static except that it hides the
* instance method declared in the AttributeHandler interface and a
* class method cannot hide an instance method.
*
* @param type the element type to which the named attribute applies
* @param name the name of the attribute
* @param value the object value to be converted to a string
* @param attrtype the type of the attribute
* @return a string representation of the supplied value
*/
public String convertValue(int type, String name, Object value, int attrtype) {
String stringValue = null;
switch(attrtype) {
case BOX_TYPE:
if(value instanceof GrappaBox) {
stringValue = ((GrappaBox)value).toAttributeString();
} else {
throw new IllegalArgumentException(“value of attribute \”” + name + “\” is not an instance of GrappaBox”);
}
break;
case COLOR_TYPE:
if(value instanceof java.awt.Color) {
stringValue = GrappaColor.getColorName((java.awt.Color)value);
} else {
throw new IllegalArgumentException(“value of attribute \”” + name + “\” is not an instance of Color”);
}
break;
case DIR_TYPE:
if(value instanceof Integer) {
stringValue = GrappaSupport.xlateDir(((Integer)value).intValue());
} else {
throw new IllegalArgumentException(“value of attribute \”” + name + “\” is not an instance of Integer”);
}
break;
case DOUBLE_TYPE:
if(value instanceof Double) {
stringValue = GrappaSupportPrintf.sprintf(new Object[] { “%g”, value });
} else {
throw new IllegalArgumentException(“value of attribute \”” + name + “\” is not an instance of Double”);
}
break;
case FONTSTYLE_TYPE:
if(value instanceof Integer) {
stringValue = GrappaSupport.xlateFontStyle(((Integer)value).intValue());
} else {
throw new IllegalArgumentException(“value of attribute \”” + name + “\” is not an instance of Integer”);
}
break;
case HASHLIST_TYPE:
if(value instanceof Hashtable) {
StringBuffer strbuf = new StringBuffer();
Enumeration keys = ((Hashtable)value).keys();
synchronized(strbuf) {
while(keys.hasMoreElements()) {
if(strbuf.length() > 0)
strbuf.append(‘,’);
strbuf.append((String)(keys.nextElement()));
}
stringValue = strbuf.toString();
}
} else {
throw new IllegalArgumentException(“value of attribute \”” + name + “\” is not an instance of Hashtable”);
}
break;
case INTEGER_TYPE:
if(value instanceof Integer) {
stringValue = ((Integer)value).toString();
} else {
throw new IllegalArgumentException(“value of attribute \”” + name + “\” is not an instance of Integer”);
}
break;
case LINE_TYPE:
if(value instanceof GrappaLine) {
stringValue = ((GrappaLine)value).toAttributeString();
} else {
throw new IllegalArgumentException(“value of attribute \”” + name + “\” is not an instance of GrappaLine”);
}
break;
case POINT_TYPE:
if(value instanceof GrappaPoint) {
stringValue = ((GrappaPoint)value).toAttributeString();
} else {
throw new IllegalArgumentException(“value of attribute \”” + name + “\” is not an instance of GrappaPoint”);
}
break;
case SHAPE_TYPE:
if(value instanceof Integer) {
stringValue = (String)Grappa.shapeToKey.get(value);
} else {
throw new IllegalArgumentException(“value of attribute \”” + name + “\” is not an instance of Integer”);
}
break;
case SIZE_TYPE:
if(value instanceof GrappaSize) {
stringValue = ((GrappaSize)value).toAttributeString();
} else {
throw new IllegalArgumentException(“value of attribute \”” + name + “\” is not an instance of GrappaSize”);
}
break;
case STRING_TYPE:
if(value instanceof String) {
stringValue = (String)value;
} else {
throw new IllegalArgumentException(“value of attribute \”” + name + “\” is not an instance of String”);
}
break;
case STYLE_TYPE:
if(value instanceof GrappaStyle) {
stringValue = ((GrappaStyle)value).toAttributeString();
} else {
throw new IllegalArgumentException(“value of attribute \”” + name + “\” is not an instance of GrappaStyle”);
}
break;
default:
if(Attribute.specialHandler != null) {
stringValue = Attribute.specialHandler.convertValue(type, name, value, attrtype);
} else {
throw new RuntimeException(Element.typeString(type,true) + ” attribute (” + name + “) needs a special handler”);
}
}
if(stringValue == null && value != null) {
if(value instanceof String) {
stringValue = (String)value;
} else {
throw new RuntimeException(“AttributeHandler needed to perform conversion of attribute \”” + name + “\”, please supply one via Attribute.setAttributeHandler()”);
}
}
return stringValue;
}
/**
* Convert the supplied string value to the appropriate Object.
* How to convert the value is
* based on the type, name and attrtype information supplied. Note: this
* method really could be declared static except that it hides the
* instance method declared in the AttributeHandler interface and a
* class method cannot hide an instance method.
*
* @param type the element type to which the named attribute applies
* @param name the name of the attribute
* @param value the string value to be converted to an object
* @param attrtype the type of the attribute
* @return an object representation of the supplied value
*/
public Object convertStringValue(int type, String name, String stringValue, int attrtype) {
Object value = null;
if(stringValue == null || (stringValue != null && attrtype != STRING_TYPE && stringValue.trim().length() == 0)) {
value = null;
stringValue = null;
} else {
switch(attrtype) {
case BOX_TYPE:
// stringValue is x1, y1, x2, y2
value = new GrappaBox(stringValue, false);
break;
case COLOR_TYPE:
value = GrappaColor.getColor(stringValue,null);
break;
case DIR_TYPE:
value = new Integer(GrappaSupport.xlateDirString(stringValue));
break;
case DOUBLE_TYPE:
try {
value = Double.valueOf(stringValue);
}
catch(NumberFormatException nfe) {
throw new IllegalArgumentException(“bad number format (” + stringValue + “) for attribute \”” + name + “\””);
}
break;
case FONTSTYLE_TYPE:
value = new Integer(GrappaSupport.xlateFontStyleString(stringValue));
break;
case HASHLIST_TYPE:
String[] listvals = GrappaSupport.strsplit(stringValue);
if(this.value != null && this.value instanceof Hashtable) {
// is this more efficient than creating a new one??
// does this introduce the danger of users being
// tempted to hold on to the value??
value = this.value;
((Hashtable)value).clear();
} else {
value = new Hashtable();
}
for(int i=0; i
* If you received this software without first entering into a license
* with AT&T, you have an infringing copy of this software and cannot use
* it without violating AT&T’s intellectual property rights.
*/
package att.grappa;
import java.util.Hashtable;
/**
* An interface for methods that perform attribute value conversions.
*
* @version 1.2, 26 May 2005; Copyright 1996 – 2005 by AT&T Corp.
* @author John Mocenigo, Research @ AT&T Labs
*/
public interface AttributeHandler
{
/**
* Convert the supplied value to a string. How to convert the value is
* based on the type, name and attrtype information supplied. Note: this
* method really could be declared static except that it hides the
* instance method declared in the AttributeHandler interface and a
* class method cannot hide an instance method.
*
* @param elemType the element type to which the named attribute applies
* @param name the name of the attribute
* @param value the object value to be converted to a string
* @param convType the object-to-string conversion type of the value object
* @return a string representation of the supplied value
*/
public String convertValue(int elemType, String name, Object value, int convType);
/**
* Convert the supplied string value to the appropriate Object.
* How to convert the value is
* based on the type, name and attrtype information supplied. Note: this
* method really could be declared static except that it hides the
* instance method declared in the AttributeHandler interface and a
* class method cannot hide an instance method.
*
* @param elemType the element type to which the named attribute applies
* @param name the name of the attribute
* @param value the string value to be converted to an object
* @param convType the string-to-object conversion type of the value object
* @return an object representation of the supplied value
*/
public Object convertStringValue(int elemType, String name, String stringValue, int convType);
/**
* Make a copy of the supplied value. How to copy the value is
* based on the type, name and attrtype information supplied. Note: this
* method really could be declared static except that it hides the
* instance method declared in the AttributeHandler interface and a
* class method cannot hide an instance method.
*
* @param elemType the element type to which the named attribute applies
* @param name the name of the attribute
* @param value the attribute value to be copied
* @param convType the conversion type of the value object
* @return a copy of the supplied value
*/
public Object copyValue(int elemType, String name, Object value, int convType);
}
att/grappa/CustomRenderer.java
att/grappa/CustomRenderer.java/*
* This software may only be used by you under license from AT&T Corp.
* (“AT&T”). A copy of AT&T’s Source Code Agreement is available at
* AT&T’s Internet website having the URL:
*
* If you received this software without first entering into a license
* with AT&T, you have an infringing copy of this software and cannot use
* it without violating AT&T’s intellectual property rights.
*/
package att.grappa;
/**
* An interface for describing the drawing of custom shapes that cannot
* be captured via a single GeneralPath. This interface would generally
* be used when the Attribute SHAPE_ATTR=custom and CUSTOM_ATTR is set to
* the name of a user provided class which would be an extension of
* GrappaShape and implements this interface. Note that if the custom shape
* desired by the user can be expressed as a single general path, then there
* is no need to use this interface or provide the methods it requires.
*
* @version 1.2, 26 May 2005; Copyright 1996 – 2005 by AT&T Corp.
* @author John Mocenigo, Research @ AT&T Labs
*/
public interface CustomRenderer
{
/**
* The method called when the element needs to be drawn.
* When used with an extention of GrappaShape,
* the default behavior is obtained by:
*
* public void draw(java.awt.Graphics2D g2d) { * g2d.draw(this); * } *
*
* @param g2d the Graphics2D context to be used for drawing
*/
public void draw(java.awt.Graphics2D g2d);
/**
* The method called when the element needs to be filled.
* When used with an extention of GrappaShape,
* the default behavior is obtained by:
*
* public void fill(java.awt.Graphics2D g2d) { * g2d.fill(this); * } *
*
* @param g2d the Graphics2D context to be used for drawing
*/
public void fill(java.awt.Graphics2D g2d);
/**
* The method called when the element needs to draw its background
* image.
* When used with an extention of GrappaShape that provides
* the underlying element as a global variable, the default behavior
* is obtained by:
*
* public void drawImage(java.awt.Graphics2D g2d) { * Rectangle sbox = this.getBounds(); * Shape clip = g2d.getClip(); * g2d.clip(this); * g2d.drawImage(element.getGrappaNexus().getImage(), sbox.x, sbox.y, sbox.width, sbox.height, null); * g2d.setClip(clip); * } *
*
* @param g2d the Graphics2D context to be used for drawing
*/
public void drawImage(java.awt.Graphics2D g2d);
}
att/grappa/Edge.java
att/grappa/Edge.java/*
* This software may only be used by you under license from AT&T Corp.
* (“AT&T”). A copy of AT&T’s Source Code Agreement is available at
* AT&T’s Internet website having the URL:
*
* If you received this software without first entering into a license
* with AT&T, you have an infringing copy of this software and cannot use
* it without violating AT&T’s intellectual property rights.
*/
package att.grappa;
import java.util.*;
import java.io.*;
/**
* This class describes an edge.
*
* @version 1.2, 26 May 2005; Copyright 1996 – 2005 by AT&T Corp.
* @author John Mocenigo, Research @ AT&T Labs
*/
public class Edge extends Element
{
/**
* Default edge name prefix used by setName().
*
* @see Edge#setName()
*/
public final static String defaultNamePrefix = “E”;
/*
* end nodes (port Ids are not used yet)
*/
private Node headNode;
private String headPortId = null;
private Node tailNode;
private String tailPortId = null;
private String key = null;
/*
* direction info (adjusted here and by GrappaNexus)
*/
int direction = GrappaLine.NONE_ARROW_EDGE;
/**
* Use this constructor when creating an edge.
*
* @param subg the parent subgraph.
* @param tail node anchoring the tail of the edge.
* @param head node anchoring the head of the edge.
*/
public Edge(Subgraph subg, Node tail, Node head) {
this(subg,tail,null,head,null,null,null);
}
/**
* Use this constructor when creating an edge with ports.
*
* @param subg the parent subgraph.
* @param tail node anchoring the tail of the edge.
* @param tailPort the port to use within the tail node.
* @param head node anchoring the head of the edge.
* @param headPort the port to use within the head node.
*/
public Edge(Subgraph subg, Node tail, String tailPort, Node head, String headPort) {
this(subg,tail,tailPort,head,headPort,null,null);
}
/**
* Use this constructor when creating an edge requiring a key to distinguish it.
*
* @param subg the parent subgraph.
* @param tail node anchoring the tail of the edge.
* @param tailPort the port to use within the tail node.
* @param head node anchoring the head of the edge.
* @param headPort the port to use within the head node.
* @param key identifier (used in conjection with tail/head, but not ports) to uniquely define edge (and prevent unwanted duplicate from being created)
*/
public Edge(Subgraph subg, Node tail, String tailPort, Node head, String headPort, String key) throws RuntimeException {
this(subg,tail,tailPort,head,headPort,key,null);
}
/**
* Use this constructor when creating an edge with a supplied unique name for easy look-up (the name is also used as the key).
*
* @param subg the parent subgraph.
* @param tail node anchoring the tail of the edge.
* @param head node anchoring the head of the edge.
* @param name identifier to uniquely define edge within the entire graph (reather than just between head/tail pairs)
*/
public Edge(Subgraph subg, Node tail, Node head, String name) throws RuntimeException {
this(subg,tail,null,head,null,null,name);
}
/**
* Use this constructor when creating an edge requiring a key to distinguish it and a supplied lookup name.
* When name is null, it is automatically generated. When key is null, it is automatically generated or set to name, if it was supplied.
*
* @param subg the parent subgraph.
* @param tail node anchoring the tail of the edge.
* @param tailPort the port to use within the tail node.
* @param head node anchoring the head of the edge.
* @param headPort the port to use within the head node.
* @param key identifier (used in conjection with tail/head, but not ports) to uniquely define edge (and prevent unwanted duplicate from being created)
* @param name a unique name that can be used for lookup (if null, automatically generated)
*/
public Edge(Subgraph subg, Node tail, String tailPort, Node head, String headPort, String key, String name) throws RuntimeException {
super(Grappa.EDGE,subg);
boolean directed = subg.getGraph().isDirected();
if(directed)
direction = GrappaLine.TAIL_ARROW_EDGE;
else
direction = GrappaLine.NONE_ARROW_EDGE;
if(subg.getGraph().isStrict()) {
if(tail == head) {
throw new RuntimeException(“cannot create self-looping edge in a strict graph (” + tail.getName() + (directed?”->”:”–“) + head.getName() + “)”);
} else {
Enumeration enm = Edge.findEdgesByEnds(tail,head);
if(enm.hasMoreElements()) {
if(!directed) {
throw new RuntimeException(“cannot create multiple edges between the same nodes in a strict graph”);
} else {
Edge tmpedge = null;
while(enm.hasMoreElements()) {
tmpedge = (Edge)enm.nextElement();
if(tmpedge.getHead() == head && tmpedge.getTail() == tail) {
throw new RuntimeException(“cannot create multiple edges between the same nodes in the same direction in a strict directed graph”);
}
}
}
}
}
}
if(!directed && tail.getId() > head.getId()) {
Node tmpNode = tail;
tail = head;
head = tmpNode;
String tmpPort = tailPort;
tailPort = headPort;
headPort = tmpPort;
}
tailNode = tail;
if(tailPort != null) {
tailPortId = new String(tailPort);
}
headNode = head;
if(headPort != null) {
headPortId = new String(headPort);
}
if(name != null) {
if(subg.getGraph().findEdgeByName(name) != null) {
throw new RuntimeException(“cannot create edge with duplicate name ‘” + name + “‘ (” + tailNode.getName() + ” -> ” + headNode.getName() + “)”);
}
this.name = name;
subg.addEdge(this);
if(key == null) {
key = name;
}
} else {
setName();
}
if(key == null) {
if(headPort != null && tailPort != null) {
this.key = tailPort + “::” + headPort;
} else if(headPort != null) {
this.key = “::” + headPort;
} else if(tailPort != null) {
this.key = tailPort + “::”;
} else {
this.key = name;
}
} else {
this.key = key;
}
if(this.key != null) {
if(findEdgeByKey(tailNode,headNode,this.key) != null) {
subg.removeEdge(this.name);
throw new RuntimeException(“cannot create duplicate edge (” + tailNode.getName() + (directed?”->”:”–“) + headNode.getName() + “) with key ‘” + this.key + “‘”);
}
}
tailNode.addEdge(this,false);
headNode.addEdge(this,true);
edgeAttrsOfInterest();
}
// a listing of the attributes of interest for Edges
private void edgeAttrsOfInterest() {
attrOfInterest(POS_ATTR);
attrOfInterest(DIR_ATTR);
attrOfInterest(LP_ATTR);
attrOfInterest(HEADLABEL_ATTR);
attrOfInterest(HEADLP_ATTR);
attrOfInterest(TAILLABEL_ATTR);
attrOfInterest(TAILLP_ATTR);
attrOfInterest(STYLE_ATTR);
}
/**
* Returns the edge with the given tail node, head node and key.
*
* @param tail the tail node of the desired edge.
* @param head the head node of the desired edge.
* @param key the key specifying the desired edge.
* @return the Edge matching the arguments or null, if there is no match.
* @see Edge#findEdgesByEnds
*/
public static Edge findEdgeByKey(Node tail, Node head, String key) {
if(tail == null || head == null || key == null) {
return(null);
}
return tail.findOutEdgeByKey(head,key);
}
/**
* Check if this element is an edge.
* Useful for testing the subclass type of a Element object.
*
* @return true if this object is a Edge.
*/
public boolean isEdge() {
return(true);
}
/**
* Get the type of this element.
* Useful for distinguishing Element objects.
*
* @return the class variable constant Grappa.EDGE.
* @see Grappa
*/
public int getType() {
return(Grappa.EDGE);
}
/**
* Generates and sets the name for this edge.
* The generated name is the concatenation of tail node name,
* the separator “>>”, the head node name, the separator “##”,
* and the id of this edge Instance.
* Also, takes the opportunity to add the edge to the subgraph and node
* dictionaries.
* Implements the abstract Element method.
*
* @see Element#getId()
*/
void setName() {
String oldName = name;
while(true) {
name = Edge.defaultNamePrefix + getId() + “_” + System.currentTimeMillis();
if(getGraph().findEdgeByName(name) == null) {
break;
}
}
// update subgraph edge dictionary
if(oldName != null) {
getSubgraph().removeEdge(oldName);
}
getSubgraph().addEdge(this);
canonName = null;
}
/**
* Get the key for this edge.
*
* @return the key of the edge
*/
public String getKey() {
return key;
}
/**
* Get the node at the head end of the edge.
*
* @return the head node of the edge
*/
public Node getHead() {
return headNode;
}
/**
* Get the head port id of the edge.
*
* @return the head port id of the edge
*/
public String getHeadPortId() {
return headPortId;
}
/**
* Get the node at the tail end of the edge.
*
* @return the tail node of the edge
*/
public Node getTail() {
return tailNode;
}
/**
* Get the tail port id of the edge.
*
* @return the tail port id of the edge
*/
public String getTailPortId() {
return tailPortId;
}
/**
* Get the String rendition of the edge.
*
* @return the string rendition of the edge, quoted as needed.
*/
public String toString() {
if(canonName == null) {
String tail = null;
String head = null;
if(tailPortId == null) {
tail = tailNode.toString();
} else {
tail = tailNode.toString() + “:” + canonString(tailPortId);
}
if(headPortId == null) {
head = headNode.toString();
} else {
head = headNode.toString() + “:” + canonString(headPortId);
}
if(getGraph().isDirected()) {
canonName = tail + ” -> ” + head;
} else {
canonName = tail + ” — ” + head;
}
}
return(canonName);
}
/**
* Print the edge description to the provided stream.
*
* @param out the output stream for writing the description.
*/
public void printEdge(PrintWriter out) {
this.printElement(out);
}
/**
* Check if the edge connects in the forward direction.
*
* @return true when edge connects in the forward direction (tail to head)
*/
public boolean goesForward() {
return(direction != GrappaLine.HEAD_ARROW_EDGE);
}
/**
* Check if the edge connects in the reverse direction.
*
* @return true when edge connects in the reverse direction (head to tail)
*/
public boolean goesReverse() {
return(direction != GrappaLine.TAIL_ARROW_EDGE);
}
/**
* Returns the attribute conversion type for the supplied attribute name.
* After edge specific attribute name/type mappings are checked, mappings
* at the element level are checked.
*
* @param attrname the attribute name
* @return the currently associated attribute type
*/
public static int attributeType(String attrname) {
int convtype = -1;
int hashCode;
if(attrname != null) {
hashCode = attrname.hashCode();
if(hashCode == POS_HASH && attrname.equals(POS_ATTR)) {
convtype = LINE_TYPE;
} else if(hashCode == MINLEN_HASH && attrname.equals(MINLEN_ATTR)) {
convtype = INTEGER_TYPE;
} else if(hashCode == DIR_HASH && attrname.equals(DIR_ATTR)) {
convtype = DIR_TYPE;
} else if(hashCode == WEIGHT_HASH && attrname.equals(WEIGHT_ATTR)) {
convtype = DOUBLE_TYPE;
} else if(hashCode == HEADLABEL_HASH && attrname.equals(HEADLABEL_ATTR)) {
convtype = STRING_TYPE;
} else if(hashCode == HEADLP_HASH && attrname.equals(HEADLP_ATTR)) {
convtype = POINT_TYPE;
} else if(hashCode == TAILLABEL_HASH && attrname.equals(TAILLABEL_ATTR)) {
convtype = STRING_TYPE;
} else if(hashCode == TAILLP_HASH && attrname.equals(TAILLP_ATTR)) {
convtype = POINT_TYPE;
} else {
return(Element.attributeType(attrname));
}
}
return(convtype);
}
/**
* Returns an enumeration of edges that have one end fixed at node1
* and the other end at node2. If node2 is empty, an enumeration of
* all edges attached to node1 is returned.
*
* @param node1 one vertex of the set of edges to be returned
* @param node2 the other vertex of the set of edges to be returned,
* or null for no constraint on the other vertex
* @return an enumeration of Edge objects.
*/
public static Enumeration findEdgesByEnds(Node node1, Node node2) {
if(node1 == null) {
return Grappa.emptyEnumeration.elements();
}
return new Enumerator(node1,node2);
}
static class Enumerator implements Enumeration {
Node node1 = null;
Node node2 = null;
Edge next = null;
Enumeration outEdges = null;
Enumeration inEdges = null;
Enumerator(Node node1, Node node2) {
this.node1 = node1;
this.node2 = node2;
if(node1 != null) {
this.outEdges = node1.outEdgeElements();
this.inEdges = node1.inEdgeElements();
next = getNext();
}
}
private Edge getNext() {
Edge tmpEdge = null;
if(outEdges != null) {
while(outEdges.hasMoreElements()) {
tmpEdge = (Edge)outEdges.nextElement();
if(node2 == null || tmpEdge.getHead() == node2) {
return tmpEdge;
}
}
outEdges = null;
}
if(inEdges != null) {
while(inEdges.hasMoreElements()) {
tmpEdge = (Edge)inEdges.nextElement();
if(node2 == null || tmpEdge.getTail() == node2) {
return tmpEdge;
}
}
inEdges = null;
}
return null;
}
public boolean hasMoreElements() {
return(next != null);
}
public Object nextElement() {
if(next == null) {
throw new NoSuchElementException(“Node$Enumerator”);
}
Edge edge = next;
next = getNext();
return edge;
}
}
}
att/grappa/Element.java
att/grappa/Element.java/*
* This software may only be used by you under license from AT&T Corp.
* (“AT&T”). A copy of AT&T’s Source Code Agreement is available at
* AT&T’s Internet website having the URL:
*
* If you received this software without first entering into a license
* with AT&T, you have an infringing copy of this software and cannot use
* it without violating AT&T’s intellectual property rights.
*/
package att.grappa;
import java.io.*;
import java.util.*;
/**
* This abstract class is the root class for the
* Node,
* Edge,
* Subgraph and
* Graph classes.
* It is the basis for describing the graph elements.
*
* @version 1.2, 26 May 2005; Copyright 1996 – 2005 by AT&T Corp.
* @author John Mocenigo, Research @ AT&T Labs
*/
public abstract class Element
implements att.grappa.GrappaConstants
{
// the containing graph and the parent subgraph element
private Graph graph = null;
private Subgraph subgraph = null;
// used for checking whether we’ve been here for dfs/bfs
long visastamp = -1L;
/*
* These (deleteCalled and busy) used by reserve/release/setDelete to
* queue a delete request during a critical function (e.g., drawing) and
* to define the start and end of that critical function.
*/
private boolean deleteCalled = false;
private boolean busy = false;
/*
* A look-up table that allows a user (via setUserAttributeType) to
* associate a String-to-Object and vice versa translation for
* attributes they may supply.
*/
private static Hashtable userAttributeTypeMap = null;
/**
* A general-purpose object not used by Grappa and intended for
* application writers to attach whatever they want to an Element
* without the need for extending the class.
*/
public Object object;
/**
* Indicates whether this element should be considered visible or not.
* If not visible, it will not be drawn and will not be selected by a
* mouse click (if the supplied selection methods are used). Note that
* there is redundancy here with the invis component of the
* style attribute. This value must be true and invis
* must be false for the element to be visible.
*/
public boolean visible = true;
/**
* Indicates whether this element should be considered selectable or not.
* The default is true.
*/
public boolean selectable = true;
/**
* Indicates indicates line width for element (for nodes or subgraphs,
* it is the outline width, when applicable).
* The default is 0 (single pixel).
*/
public int linewidth = 0;
/**
* Indicates whether only the list of attributes found in the
* PRINTLIST_ATTR should be printed.
* The default is false.
*/
public static boolean usePrintList = false;
/**
* A convenience variable, not used by Grappa, but available to keep
* track of or otherwise mark graph elements when traversing a graph.
*/
public int counter = 0;
/**
* Determines the type of highlighting to apply, if any, when drawing.
* Currently recognized choices are SELECTION_MASK and DELETION_MASK.
*/
public int highlight = 0;
// identification
private Long idKey = null;
String name = null;
// attributes
Hashtable attributes = null;
// attributes
Hashtable attrsOfInterest = null;
// the Shape for drawing
GrappaNexus grappaNexus = null;
/**
* Boolean to indicate if all of this element’s attributes should
* be printed. Either this flag or the elementPrintAllAttributes
* can turn on printing of all attributes.
*
* @see Subgraph#printSubgraph
* @see Grappa#elementPrintAllAttributes
*/
public boolean printAllAttributes = false;
/**
* Boolean to indicate if the default attributes associated with
* this element should be printed. Naturally, this option only
* is effective if the element is a subgraph.
*
* @see Subgraph#printSubgraph
* @see Grappa#elementPrintDefaultAttributes
*/
public boolean printDefaultAttributes = false;
// canonical name
String canonName = null;
/**
* Element constructor needed only during init phase of
* Graph class.
* Since the Element class is abstact, it cannot be instantiated directly.
*/
protected Element() {
// needed due to Graph init (a special case of Subgraph)
}
/**
* Element constructor used during init phase of the
* Node,
* Edge and
* Subgraph classes.
* Since the Element class is abstact, it cannot be instantiated directly.
*
* @param type the type of the element (Grappa.NODE, Grappa.EDGE or Grappa.SUBGRAPH).
* @param subg the subgraph containing this element.
*
* @see GrappaConstants#NODE
* @see GrappaConstants#EDGE
* @see GrappaConstants#SUBGRAPH
*/
protected Element(int type, Subgraph subg) {
//super();
setSubgraph(subg);
setGraph(subg.getGraph());
setIdKey(type);
getGraph().addIdMapping(this);
elementAttrsOfInterest();
}
// set the attributes of interest to all elements
private void elementAttrsOfInterest() {
attrOfInterest(COLOR_ATTR);
attrOfInterest(FONTCOLOR_ATTR);
attrOfInterest(FONTNAME_ATTR);
attrOfInterest(FONTSIZE_ATTR);
attrOfInterest(FONTSTYLE_ATTR);
attrOfInterest(LABEL_ATTR);
}
/**
* Get the type of this Element. Useful for distinguishing Element objects.
*
* @return the appropriate class variable constant
*
* @see GrappaConstants#NODE
* @see GrappaConstants#EDGE
* @see GrappaConstants#SUBGRAPH
*/
public abstract int getType();
/**
* Check if this Element is a node. Overridden in Node to return true.
*
* @return false, unless overridden.
*
* @see Node#isNode()
*/
public boolean isNode() {
return(false);
}
/**
* Check if this Element is an edge. Overridden in Edge to return true.
*
* @return false, unless overridden.
*
* @see Edge#isEdge()
*/
public boolean isEdge() {
return(false);
}
/**
* Check if this Element is a subgraph. Overridden in Subgraph to return true.
*
* @return false, unless overridden.
*
* @see Subgraph#isSubgraph()
*/
public boolean isSubgraph() {
return(false);
}
/**
* Intended to be a subclass-specific name generating method.
* Used by edges and when nodes or graphs are created without
* an explicit name.
* Note that graphs and nodes should also have a setName that
* takes an explicit name as an argument.
*/
abstract void setName();
/**
* Get the name of this Element.
*
* @return the name of the element.
*/
public String getName() {
return(name);
}
/**
* Check if this Element can be reserved, otherwise queue request
*
* @return true, if successfully reserved.
*/
boolean reserve() {
return setReserved(true, false);
}
/**
* Release the reservation on this Element, if any.
*/
void release() {
setReserved(false, false);
}
/**
* Queue or unqueue a delete request.
*
* @return true, unless a delete request has already been queued
* for this Element.
*/
boolean setDelete(boolean delete) {
return setReserved(delete, true);
}
// handle the reserve/release/setDelete requests
private synchronized boolean setReserved(boolean state, boolean isDelete) {
if(isDelete) {
if(state) {
deleteCalled = true;
if(busy) {
return(false);
} else {
return(busy = true);
}
} else {
deleteCalled = busy = false;
return(true);
}
} else if(state) {
if(deleteCalled) return(false);
return(busy = true);
} else {
if(!deleteCalled) {
busy = false;
} else {
busy = deleteCalled = false;
delete();
}
return(true);
}
}
/**
* Add the name of an attribute of interest to this element
*
* @param name the name of the attribute
*/
protected void attrOfInterest(String name) {
if(name == null || isOfInterest(name)) return;
if(attrsOfInterest == null) {
attrsOfInterest = new Hashtable();
}
attrsOfInterest.put(name,name);
if(grappaNexus != null) {
Attribute attr = getAttribute(name);
if(attr != null) {
attr.addObserver(grappaNexus);
}
}
}
/**
* Remove the name of an attribute of interest to this object
*
* @param name the name of the attribute
*/
protected void attrNotOfInterest(String name) {
if(name == null || !isOfInterest(name)) return;
if(grappaNexus != null) {
Attribute attr = getAttribute(name);
if(attr != null) attr.deleteObserver(grappaNexus);
}
attrsOfInterest.remove(name);
}
/**
* Provide an enumeration of the names of the attributes of interest.
*
* @return an enumeration of attribute names that are of interest
*/
public Enumeration listAttrsOfInterest() {
if(attrsOfInterest == null) return Grappa.emptyEnumeration.elements();
return attrsOfInterest.elements();
}
/**
* Check if the name of an attribute of interest to this object
*
* @param name the name of the attribute
* @return true when the name is of interest
*/
public boolean isOfInterest(String name) {
if(name == null || attrsOfInterest == null) return false;
return attrsOfInterest.contains(name);
}
/**
* Sets or creates an attribute for this element from the attribute supplied.
* The storage key is the attribute name. If the value portion of the
* supplied attribute is null, then the attribute will be removed from the
* element.
*
* @param attr the attribute from which to set the element’s attribute.
* @return the value of the (local) attribute previously stored
* under the same name
*/
public Object setAttribute(Attribute attr) {
if(attr == null) {
return null;
}
return setAttribute(attr.getName(),attr.getValue());
}
/**
* Sets or creates an attribute for this element from the supplied
* arguments. The storage key is the attribute name. If the value
* argument is null, then the attribute will be removed from the element.
*
* @param name the attribute name
* @param value the attribute value
* @return the value of the (local) attribute previously stored
* under the same name
*/
public Object setAttribute(String name, Object value) {
if(attributes == null) {
attributes = new Hashtable();
}
if(name == null) {
throw new IllegalArgumentException(“cannot set an attribute using a null name”);
}
Object oldValue = null;
Attribute crntAttr = getLocalAttribute(name);
if(crntAttr == null) {
if(value == null) {
return null;
} else if(value instanceof String && ((String)value).trim().length() == 0 && Attribute.attributeType(getType(),name) != STRING_TYPE) {
return null;
}
attributes.put(name,(crntAttr = new Attribute(getType(),name,value)));
if(grappaNexus != null && isOfInterest(name)) {
crntAttr.addObserver(grappaNexus);
}
} else {
oldValue = crntAttr.getValue();
if(value == null) {
//System.err.println(“direct removal of (“+name+”,”+value+”) from “+getName());
removeAttribute(name);
return oldValue;
} else if(value instanceof String && ((String)value).trim().length() == 0 && Attribute.attributeType(getType(),name) != STRING_TYPE) {
//System.err.println(“removal of (“+name+”,”+value+”) from “+getName());
removeAttribute(name);
return oldValue;
} else {
crntAttr.setValue(value);
}
}
if(crntAttr.hasChanged()) {
crntAttr.notifyObservers(new Long(System.currentTimeMillis()));
}
return oldValue;
}
/*
* Removes the named attribute from the (local) attribute table and
* applies the default attribute (if any)
*
* @param name the name of the attribute to be removed.
* @return the default attribute pair for this attribute.
*/
private Attribute removeAttribute(String name) {
if(name == null) return null;
Attribute dfltAttr = getDefaultAttribute(name);
Attribute attr = null;
if(attributes != null) attr = (Attribute)attributes.remove(name);
if(attr == null) return dfltAttr;
if(dfltAttr == null) {
attr.setValue(“”);
}
attr.setChanged();
attr.notifyObservers(new Object[] { dfltAttr, new Long(System.currentTimeMillis()) });
return dfltAttr;
}
/**
* Sets or creates a default attribute for this element type within the
* containing subgraph of this element from the supplied arguments.
* The storage key is the attribute name.
* If the value argument is null, then the
* attribute will be removed from the subgraph.
*
* @param name the attribute name
* @param value the attribute value
* @return the value of the (default) attribute previously stored
* under the same name
*/
public Object setDefaultAttribute(String name, Object value) {
return setDefaultAttribute(getType(),name,value);
}
/**
* Sets or creates a default attribute of the specified type within the
* containing subgraph of this element from the supplied arguments.
* The storage key is the attribute name.
* If the value argument is null, then the
* attribute will be removed from the subgraph.
*
* @param type the default attribute type
* @param name the attribute name
* @param value the attribute value
* @return the value of the (default) attribute previously stored
* under the same name
*/
public Object setDefaultAttribute(int type, String name, Object value) {
Object oldValue = null;
Subgraph subg = getSubgraph();
switch(type) {
case Grappa.NODE:
oldValue = subg.setNodeAttribute(name,value);
break;
case Grappa.EDGE:
oldValue = subg.setEdgeAttribute(name,value);
break;
case Grappa.SUBGRAPH:
// ignore subg == null (i.e., root subgraph case)
if(subg != null) {
oldValue = subg.setAttribute(name,value);
}
break;
}
return oldValue;
}
/**
* Sets or creates a default attribute for this element type within the
* containing subgraph of this element from the supplied arguments.
* The storage key is the attribute name.
* If the value portion of the supplied attribute is null, then the
* attribute will be removed from the subgraph.
*
* @param attr the attribute to which the default should be set
* @return the value of the (default) attribute previously stored
* under the same name
*/
public Object setDefaultAttribute(Attribute attr) {
return setDefaultAttribute(getType(),attr);
}
/**
* Sets or creates a default attribute of the specified type within the
* containing subgraph of this element from the supplied arguments.
* The storage key is the attribute name.
* If the value portion of the supplied attribute is null, then the
* attribute will be removed from the subgraph.
*
* @param type the default attribute type
* @param attr the attribute to which the default should be set
* @return the value of the (default) attribute previously stored
* under the same name
*/
public Object setDefaultAttribute(int type, Attribute attr) {
if(attr == null) return null;
Object oldValue = null;
Subgraph subg = getSubgraph();
switch(type) {
case Grappa.NODE:
oldValue = subg.setNodeAttribute(attr);
break;
case Grappa.EDGE:
oldValue = subg.setEdgeAttribute(attr);
break;
case Grappa.SUBGRAPH:
// ignore subg == null (i.e., root subgraph case)
if(subg != null) {
oldValue = subg.setAttribute(attr);
}
break;
}
return oldValue;
}
/**
* Gets an enumeration of the keys for this Element’s local attributes.
*
* @return an Enumneration of String objects
*/
public Enumeration getLocalAttributeKeys() {
if(attributes == null) {
return Grappa.emptyEnumeration.elements();
}
return(attributes.keys());
}
/**
* Get an Enumeration of the Attribute objects for this Element.
*
* @return an Enumneration of the (local) Attribute objects.
*/
public Enumeration getLocalAttributePairs() {
if(attributes == null) {
return Grappa.emptyEnumeration.elements();
}
return(attributes.elements());
}
/**
* Get an enumeration of all attribute pairs for this element.
*
* @return an enumeration of local and default Attribute objects for this element.
*/
public Enumeration getAttributePairs() {
Hashtable pairs = null;
Attribute attr = null;
Enumeration enm = getLocalAttributePairs();
if(enm.hasMoreElements()) pairs = new Hashtable(32);
while(enm.hasMoreElements()) {
attr = (Attribute)enm.nextElement();
pairs.put(attr.getName(),attr);
}
switch(getType()) {
case Grappa.NODE:
enm = getSubgraph().getNodeAttributePairs();
break;
case Grappa.EDGE:
enm = getSubgraph().getEdgeAttributePairs();
break;
case Grappa.SUBGRAPH:
enm = getLocalAttributePairs();
break;
}
if(pairs != null) {
while(enm.hasMoreElements()) {
attr = (Attribute)enm.nextElement();
if(!pairs.containsKey(attr.getName())) {
pairs.put(attr.getName(),attr);
}
}
return pairs.elements();
}
return enm;
}
/**
* Get only the corresponding local attribute for the specified key. A local attribute is
* one associated directly with this element as opposed to a subgraph
* ancestor.
*
* @param key the search key for the corresponding attribute.
*
* @return the local Attribute object matching the key or null.
*/
public Attribute getLocalAttribute(String key) {
if(attributes == null) return(null);
return((Attribute)(attributes.get(key)));
}
/**
* Get only the corresponding local attribute for the specified key if
* it is not inherited from the parent, otherwise return null. Sometimes
* a local attribute will be set, but it will be a pointer to the
* parent value. This method distinguishes that case.
*
* @param key the search key for the corresponding attribute.
*
* @return the local Attribute object matching the key or null if it is not defined or it is a pointer to the parent attribute..
*/
public Attribute getThisAttribute(String key) {
Attribute attr;
Subgraph sg;
if(attributes == null) return(null);
if((attr = (Attribute)(attributes.get(key))) == null) return(null);
if((sg = getSubgraph()) == null) return(attr);
if(attr == sg.getAttribute(key)) return(null);
return(attr);
}
/**
* Get only the value of the corresponding local attribute for the
* specified key if the attribute is not inherited from the parent,
* otherwise return null. Sometimes a local attribute will be set,
* but it will be simply a pointer to the parent attribute.
* This method distinguishes that case.
*
* @param key the search key for the corresponding attribute.
*
* @return the value of the local Attribute object matching the key or null if it is not defined or it is a pointer to the parent attribute..
*/
public Object getThisAttributeValue(String key) {
Attribute attr = getThisAttribute(key);
if(attr == null) return(null);
return(attr.getValue());
}
/**
* Get the corresponding default attribute for the specified type and key.
*
* @param type the type of the default attribute
* @param key the search key for the corresponding attribute.
* @return the value of the default Attribute object matching the key or null.
*/
public Attribute getDefaultAttribute(int type, String key) {
Attribute value = null;
Subgraph sg = null;
if(isSubgraph()) sg = (Subgraph)this;
else sg = getSubgraph();
if(sg == null) {
// unattached, so try global attributes
return(Graph.getGlobalAttribute(type,key));
}
switch(type) {
case Grappa.NODE:
value = sg.getNodeAttribute(key);
break;
case Grappa.EDGE:
value = sg.getEdgeAttribute(key);
break;
case Grappa.SUBGRAPH:
value = sg.getLocalAttribute(key);
break;
}
return(value);
}
/**
* Get the default attribute of this element for the specified key.
*
* @param key the search key for the corresponding attribute.
* @return the value of the default Attribute object matching the key or null.
*/
public Attribute getDefaultAttribute(String key) {
return getDefaultAttribute(getType(),key);
}
/**
* Get the Attribute of this Element for the specified key.
* Search first local, then default attributes until a match is found.
*
* @param key the search key for the attribute.
* @return the corresponding Attribute object or null.
*/
public Attribute getAttribute(String key) {
Attribute attr = null;
if((attr = getLocalAttribute(key)) == null) {
attr = getDefaultAttribute(key);
}
return(attr);
}
/**
* Get the Attribute value of this Element for the specified key.
* Search first local, then default attributes until a match is found.
*
* @param key the search key for the attribute.
* @return the corresponding attribute value or null.
*/
public Object getAttributeValue(String key) {
Object value = null;
Attribute attr = getAttribute(key);
if(attr != null) {
value = attr.getValue();
}
return(value);
}
/**
* Checks to see if this element has an Attribute matching the key
*
* @param key the search key for the attribute.
* @return true if there is a matching attribute, false otherwise.
*/
public boolean hasAttributeForKey(String key) {
if(getAttribute(key) == null) return(false);
return(true);
}
/**
* Get the Graph of this Element.
*
* @return the containing graph object.
*/
public Graph getGraph() {
return(graph);
}
/**
* Get the containing Subgraph of this Element.
*
* @return the parent subgraph object.
*/
public Subgraph getSubgraph() {
return(subgraph);
}
/**
* Set the containing graph for this element.
*
* @param graph the overall graph that contains this element.
*/
void setGraph(Graph graph) {
this.graph = graph;
}
/**
* Set the parent subgraph for this element.
*
* @param subgraph the parent subgraph that contains this element.
*/
public void setSubgraph(Subgraph subgraph) {
if(this.subgraph != null && this.subgraph != subgraph) {
switch(this.getType()) {
case Grappa.NODE:
this.subgraph.removeNode(((Node)this).getName());
subgraph.addNode((Node)this);
break;
case Grappa.EDGE:
this.subgraph.removeEdge(((Edge)this).getName());
subgraph.addEdge((Edge)this);
break;
case Grappa.SUBGRAPH:
this.subgraph.removeSubgraph(((Subgraph)this).getName());
subgraph.addSubgraph((Subgraph)this);
break;
}
}
if(this.subgraph != subgraph) {
if(this.subgraph != null && this.subgraph.grappaNexus != null)
this.subgraph.clearBBox();
if(subgraph != null && subgraph.grappaNexus != null)
subgraph.clearBBox();
}
this.subgraph = subgraph;
}
protected void clearBBox() { // formerly resetBBox
if(grappaNexus != null) grappaNexus.bbox = null;
Subgraph prnt = getSubgraph();
while(prnt != null) {
if(prnt.grappaNexus != null) {
prnt.grappaNexus.bbox = null;
}
prnt = prnt.getSubgraph();
}
}
/**
* Get the ID number of this Element.
*
* @return the id number of this element.
*/
public int getId() {
return (int)((getIdKey().longValue())>>Grappa.TYPES_SHIFT);
}
/**
* Get the ID of this Element as a Long object.
*
* @return the id object of this element.
*/
public Long getIdKey() {
return(idKey);
}
/**
* Sets the id key of this element
*/
protected void setIdKey(int type) {
idKey = Graph.idMapKey(type,getGraph().nextId(type));
}
/**
* Print a description of this element to the given print stream.
*
* @param out the print stream for output.
*/
public void printElement(PrintWriter out) {
String indent = new String(getGraph().getIndent());
if(Grappa.printVisibleOnly && (!visible || grappaNexus.style.invis))
return;
out.print(indent + toString());
getGraph().incrementIndent();
printAttributes(out,indent);
getGraph().decrementIndent();
out.println();
}
/*
* Print attributes to given stream. A square open bracket prefix and
* closed bracket suffix enclose the attributes, but are printed only if
* there are any attributes to print. The supplied indent determines the
* indentation of the final bracket (it is assumed the element name has
* already printed to the output stream.
*
* @param out the print stream for output.
* @param outerIndent the indent to use for the prefix and suffix.
*/
private void printAttributes(PrintWriter out, String outerIndent) {
String indent = new String(getGraph().getIndent());
String prefix = ” [“;
String suffix = Grappa.NEW_LINE + outerIndent + “];”;
Attribute attr;
String key;
boolean first = true;
// thanks to Ginny Travers (bbn.com) for suggesting the printlist feature
Hashtable printlist = null;
if(Grappa.usePrintList || usePrintList) {
printlist = (Hashtable)getAttributeValue(PRINTLIST_ATTR);
}
Enumeration attrs = null;
if(Grappa.elementPrintAllAttributes || printAllAttributes) {
attrs = getAttributePairs();
} else if(attributes != null && !attributes.isEmpty()) {
attrs = attributes.elements();
}
if(attrs != null) {
while(attrs.hasMoreElements()) {
attr = (Attribute)(attrs.nextElement());
key = attr.getName();
if(printlist != null && printlist.get(key) == null) continue;
if(attr != null && (Grappa.elementPrintAllAttributes || printAllAttributes || !attr.equalsValue(getDefaultAttribute(key)))) {
if(first) {
first = false;
out.println(prefix);
} else {
out.println(“,”);
}
out.print(indent + key + ” = ” + canonString(attr.getStringValue()));
}
}
}
if(getGraph().filterMode && isEdge()) {
if(first) {
first = false;
out.println(prefix);
} else {
out.println(“,”);
}
out.print(indent + “__nAmE__ = ” + canonString(getName()));
}
if(!first) {
out.print(suffix);
}
}
/**
* Get the String rendition of the element.
*
* @return the string rendition of the element, quoted as needed.
*/
public String toString() {
if(canonName == null) {
canonName = canonString(name);
}
return(canonName);
}
/**
* Canonicalizes the supplied string for output.
*
* @param input the string to be quoted, possibly.
* @return the input string, possibly enclosed in double quotes and
* with internal double quotes protected.
*/
// essentially the agstrcanon function from libgraph (by S. C. North)
public static String canonString(String input) {
int len;
if(input == null || (len = input.length()) == 0) {
return(“\”\””);
}
StringBuffer strbuf = new StringBuffer(len + 8);
char[] array = input.toCharArray();
char ch;
boolean has_special = false;
for(int isub = 0; isub < array.length; isub++) {
if(array[isub] == '"') {
strbuf.append('\\');
has_special = true;
} else if(!has_special) {
if(!Lexer.id_char(array[isub])) {
has_special = true;
}
}
strbuf.append(array[isub]);
}
// annoying, but necessary kludge to make libgraph parser happy
if(!has_special && len <= 8) {
String low = input.toLowerCase();
if(
low.equals("node") || low.equals("edge") || low.equals("graph") ||
low.equals("digraph") || low.equals("subgraph") || low.equals("strict")
) {
has_special = true;
}
}
if(has_special) {
strbuf.append('"');
strbuf.insert(0,'"');
}
return(strbuf.toString());
}
/**
* Provides the element type as a string.
*
* @param elemType an integer value representing an element type
* @param uplow set true to indicate the return value should be
* leading-capitalized, otherwise lower-case is returned
* @return the meaning of the element type in english
*/
public final static String typeString(int elemType, boolean uplow) {
String type = null;
switch(elemType) {
case NODE:
type = uplow ? "Node" : "node";
break;
case EDGE:
type = uplow ? "Edge" : "edge";
break;
case SUBGRAPH:
type = uplow ? "Subgraph" : "subgraph";
break;
case SYSTEM:
type = uplow ? PKG_UPLOW : PKG_LOWER;
break;
default:
type = null;
}
return(type);
}
/**
* Canonicalizes the supplied string for look-up.
* NOTE: Not currently used by Grappa.
*
* @param input the string to be canonicalized.
* @return the input string, with non-alphanumerics
* removed and alphabetics are converted to lower-case.
*/
public static String canonValue(String input) {
if(input == null) return null;
char[] array = input.toCharArray();
int len = 0;
boolean allDigits = true;
for(int i = 0; i < array.length; i++) {
if(Character.isUpperCase(array[i])) {
array[len++] = Character.toLowerCase(array[i]);
allDigits = false;
} else if(Character.isLowerCase(array[i])) {
array[len++] = array[i];
allDigits = false;
} else if(Character.isDigit(array[i])) {
array[len++] = array[i];
}
}
if(len == 0 || allDigits) return null;
return new String(array,0,len);
}
/**
* Boolean inicating if a delete request has been received by this element.
*/
boolean deleteCalled() {
return deleteCalled;
}
/**
* Method for deleting an element.
* Clears element references from graph tables and frees up space explicitly.
* @see Graph#reset()
*/
public final boolean delete() {
if(!setDelete(true)) return(false);
String name = getName();
Enumeration enm = null;
if(attributes != null && grappaNexus != null) {
enm = attributes.elements();
while(enm.hasMoreElements()) {
((Attribute)enm.nextElement()).deleteObserver(grappaNexus);
}
}
Element elem = null;
Subgraph prnt = null;
// account for bounding box change due to deletion
if(grappaNexus != null) grappaNexus.bbox = null;
prnt = getSubgraph();
while(prnt != null) {
if(prnt.grappaNexus != null) prnt.grappaNexus.bbox = null;
prnt = prnt.getSubgraph();
}
switch(getType()) {
case Grappa.NODE:
enm = ((Node)this).edgeElements();
while(enm.hasMoreElements()) {
elem = (Element)(enm.nextElement());
prnt = elem.getSubgraph();
while(prnt != null) {
if(prnt.grappaNexus != null) prnt.grappaNexus.bbox = null;
prnt = prnt.getSubgraph();
}
((Edge)elem).delete();
}
getSubgraph().removeNode(name);
break;
case Grappa.EDGE:
((Edge)this).getTail().removeEdge(((Edge)this),false);
((Edge)this).getHead().removeEdge(((Edge)this),true);
getSubgraph().removeEdge(name);
break;
case Grappa.SUBGRAPH:
enm = ((Subgraph)this).nodeElements();
elem = null;
while(enm.hasMoreElements()) {
elem = (Element)enm.nextElement();
elem.delete();
}
enm = ((Subgraph)this).edgeElements();
elem = null;
while(enm.hasMoreElements()) {
elem = (Element)enm.nextElement();
elem.delete();
}
enm = ((Subgraph)this).subgraphElements();
elem = null;
while(enm.hasMoreElements()) {
elem = (Element)enm.nextElement();
elem.delete();
}
if(getSubgraph() != null) getSubgraph().removeSubgraph(name);
break;
}
getGraph().removeIdMapping(this);
if(grappaNexus != null) {
grappaNexus.element = null;
grappaNexus = null;
}
return(true);
}
/**
* Tags the element with the supplied string.
*
* @param tag the tag to associate with this Element.
*/
public void addTag(String tag) {
Attribute attr;
Hashtable tags;
if(tag == null || tag.indexOf(',') >= 0) {
throw new RuntimeException(“tag value null or contains a comma (” + tag + “)”);
}
if((attr = getLocalAttribute(TAG_ATTR)) == null) {
attr = new Attribute(getType(),TAG_ATTR,new Hashtable());
setAttribute(attr);
}
tags = (Hashtable)(attr.getValue());
tags.put(tag,tag);
// if it becomes desireable to retain the original order, we
// could always use the value in the following (instead of
// what is done above) to reconstruct the original order
// (Note that no code makes use of the value at this point,
// so that would all have to be added in printAttributes, for
// example)
// tags.put(tag,new Long(System.currentTimeMillis()));
}
/**
* Check if this Element has the supplied tag either locally or as a default.
*
* @param tag tag value to be searched for
* @return true, if this Element contains the supplied tag
*/
public boolean hasTag(String tag) {
Attribute attr;
Hashtable tags;
if(tag == null || tag.indexOf(‘,’) >= 0) {
throw new RuntimeException(“tag value null or contains a comma (” + tag + “)”);
}
if((attr = getLocalAttribute(TAG_ATTR)) == null) {
return(hasDefaultTag(tag));
}
tags = (Hashtable)(attr.getValue());
if(tags == null || tags.size() == 0) return false;
return(tags.containsKey(tag));
}
/**
* Check if this Element has the supplied tag locally.
*
* @param tag tag value to be searched for
* @return true, if this Element contains the supplied tag
*/
public boolean hasLocalTag(String tag) {
Attribute attr;
Hashtable tags;
if((attr = getLocalAttribute(TAG_ATTR)) == null) return false;
tags = (Hashtable)(attr.getValue());
if(tags == null || tags.size() == 0) return false;
return(tags.containsKey(tag));
}
/**
* Check if this Element has the supplied tag as a default tag.
*
* @param tag tag value to be searched for
* @return true, if this Element has the supplied tag as a default tag
*/
public boolean hasDefaultTag(String tag) {
Attribute attr;
Hashtable tags;
if((attr = getDefaultAttribute(TAG_ATTR)) == null) return false;
tags = (Hashtable)(attr.getValue());
if(tags == null || tags.size() == 0) return false;
return(tags.containsKey(tag));
}
/**
* Check if this Element is tagged at all either locally or with a default.
*
* @return true, if this Element is tagged at all
*/
public boolean hasTags() {
Attribute attr;
Hashtable tags;
if((attr = getLocalAttribute(TAG_ATTR)) == null) {
return(hasDefaultTags());
}
tags = (Hashtable)(attr.getValue());
if(tags == null || tags.size() == 0) return false;
return true;
}
/**
* Check if this Element is tagged at all locally.
*
* @return true, if this Element is tagged locally
*/
public boolean hasLocalTags() {
Attribute attr;
Hashtable tags;
if((attr = getLocalAttribute(TAG_ATTR)) == null) return false;
tags = (Hashtable)(attr.getValue());
if(tags == null || tags.size() == 0) return false;
return true;
}
/**
* Check if this Element has any default tags at all.
*
* @return true, if this Element has any default tags
*/
public boolean hasDefaultTags() {
Attribute attr;
Hashtable tags;
if((attr = getDefaultAttribute(TAG_ATTR)) == null) return false;
tags = (Hashtable)(attr.getValue());
if(tags == null || tags.size() == 0) return false;
return true;
}
/**
* Removes all tags locally associated with this element.
*/
public void removeTags() {
Attribute attr;
Hashtable tags;
if((attr = getLocalAttribute(TAG_ATTR)) == null) return;
tags = (Hashtable)(attr.getValue());
if(tags == null || tags.size() == 0) return;
tags.clear();
}
/**
* Removes the specified tag locally from this element.
*
* @param tag the tag value to remove
*/
public void removeTag(String tag) {
Attribute attr;
Hashtable tags;
if((attr = getLocalAttribute(TAG_ATTR)) == null) return;
tags = (Hashtable)(attr.getValue());
if(tags == null || tags.size() == 0) return;
tags.remove(tag);
}
/**
* Sets the conversion type of a user-defined attribute.
* Unless provided for a specific attribute name, the attribute value
* will only be treated as a string. When provided, the string value
* of the attribute will be converted to the given type and vice
* versa.
*
* @param attrname the attribute name
* @param attrtype the attribute type
*
* @return the previous type associated with this attribute name
*/
public static int setUserAttributeType(String attrname, int attrtype) {
int oldtype = _NO_TYPE;
Integer type = null;
if(attrname == null || attrname.trim().length() == 0) {
throw new IllegalArgumentException(“supplied attribute name should be non-null and contain some non-blank characters”);
}
if(attrtype < 0) {
type = new Integer(attrtype);
} else {
switch(attrtype) {
case _NO_TYPE:
default:
// ignore
break;
case BOX_TYPE:
case COLOR_TYPE:
case DOUBLE_TYPE:
case FONTSTYLE_TYPE:
case INTEGER_TYPE:
case LINE_TYPE:
case POINT_TYPE:
case SHAPE_TYPE:
case SIZE_TYPE:
case STRING_TYPE:
case STYLE_TYPE:
type = new Integer(attrtype);
break;
}
}
if(type == null) {
throw new IllegalArgumentException("supplied type for attribute (" + attrname + ") should be less than zero or a recognized type value");
}
if(userAttributeTypeMap == null) {
userAttributeTypeMap = new Hashtable();
}
Integer old = (Integer)(userAttributeTypeMap.get(attrname));
if(old != null) {
oldtype = old.intValue();
}
userAttributeTypeMap.put(attrname,type);
return(oldtype);
}
/**
* Returns the attribute conversion type for the supplied attribute name.
*
* @param attrname the attribute name
* @return the currently associated attribute type
*/
public static int attributeType(String attrname) {
int convtype = -1;
int hashCode;
if(attrname != null) {
hashCode = attrname.hashCode();
if(hashCode == BBOX_HASH && attrname.equals(BBOX_ATTR)) {
convtype = BOX_TYPE;
} else if(hashCode == COLOR_HASH && attrname.equals(COLOR_ATTR)) {
convtype = COLOR_TYPE;
} else if(hashCode == FILLCOLOR_HASH && attrname.equals(FILLCOLOR_ATTR)) {
convtype = COLOR_TYPE;
} else if(hashCode == FONTCOLOR_HASH && attrname.equals(FONTCOLOR_ATTR)) {
convtype = COLOR_TYPE;
} else if(hashCode == FONTSIZE_HASH && attrname.equals(FONTSIZE_ATTR)) {
convtype = INTEGER_TYPE;
} else if(hashCode == FONTSTYLE_HASH && attrname.equals(FONTSTYLE_ATTR)) {
convtype = FONTSTYLE_TYPE;
} else if(hashCode == HEIGHT_HASH && attrname.equals(HEIGHT_ATTR)) {
convtype = DOUBLE_TYPE;
} else if(hashCode == LABEL_HASH && attrname.equals(LABEL_ATTR)) {
convtype = STRING_TYPE;
} else if(hashCode == LP_HASH && attrname.equals(LP_ATTR)) {
convtype = POINT_TYPE;
} else if(hashCode == PATCH_HASH && attrname.equals(PATCH_ATTR)) {
convtype = DOUBLE_TYPE;
} else if(hashCode == PRINTLIST_HASH && attrname.equals(PRINTLIST_ATTR)) {
convtype = HASHLIST_TYPE;
} else if(hashCode == STYLE_HASH && attrname.equals(STYLE_ATTR)) {
convtype = STYLE_TYPE;
} else if(hashCode == TAG_HASH && attrname.equals(TAG_ATTR)) {
convtype = HASHLIST_TYPE;
} else if(hashCode == STYLE_HASH && attrname.equals(STYLE_ATTR)) {
} else if(hashCode == WIDTH_HASH && attrname.equals(WIDTH_ATTR)) {
convtype = DOUBLE_TYPE;
} else if(userAttributeTypeMap != null) {
Integer usertype = (Integer)(userAttributeTypeMap.get(attrname));
if(usertype == null) {
convtype = STRING_TYPE;
} else {
convtype = usertype.intValue();
}
} else {
convtype = STRING_TYPE;
}
}
return(convtype);
}
/**
* Creates and populates the GrappaNexus object for this element.
* The GrappaNexus object provides bounding and drawing information
* for the element based on the element's attributes.
*/
public void buildShape() {
if(grappaNexus == null) {
grappaNexus = new GrappaNexus(this);
Attribute attr = null;
Enumeration enm = listAttrsOfInterest();
while(enm.hasMoreElements()) {
attr = getAttribute((String)enm.nextElement());
if(attr != null) {
attr.addObserver(grappaNexus);
}
}
}
if(grappaNexus == null) {
throw new InternalError("grappaNexus did not get created");
}
}
/**
* Returns the GrappaNexus object associated with this element.
*/
public GrappaNexus getGrappaNexus() {
if(grappaNexus == null) {
buildShape();
}
return(grappaNexus);
}
/**
* Performs a breadth-first or a depth-first search starting at this Element.
*
* @param steps when negative, the search is exhaustive; otherwise the search stops after the number of steps indicated
*
* @return a Vector of Vector, the ith element of which gives the search results for step i. Reading the vector in increasing order gives breadth-first search results, while using decreasing order gives depth-first results.
*/
public Vector bdfs(int steps) {
Vector input, layers;
Element elem;
int size;
input = new Vector(1);
input.addElement(this);
layers = new Vector();
synchronized(getGraph()) {
doBDFS(getType(), steps, System.currentTimeMillis(), 0, input, layers);
}
return(layers);
}
private static void doBDFS(int type, int depth, long stamp, int level, Vector inbox, Vector layers) {
Element elem;
Subgraph subg;
Edge edge;
Node node;
int sz, szz;
Enumeration enm;
Vector input;
if((sz = inbox.size()) == 0)
return;
layers.addElement(inbox);
level++;
if(depth >= 0 && level > depth)
return;
input = new Vector();
for(int i=0; i
doBDFS(type, depth, stamp, level, input, layers);
}
//
// Start PatchWork stuff
//
private double patchSize = 0;
double getPatchSize() {
return(patchSize);
}
void setPatchSize(double val) {
patchSize = val;
}
private java.awt.geom.Rectangle2D.Double patch = null;
java.awt.geom.Rectangle2D.Double getPatch() {
return(patch);
}
void setPatch(java.awt.geom.Rectangle2D.Double p) {
if(p == null)
patch = p;
else if(patch == null)
patch = new GrappaBox(p.getX(), p.getY(), p.getWidth(), p.getHeight());
else
patch.setRect(p.getX(), p.getY(), p.getWidth(), p.getHeight());
}
void setPatch(double x, double y, double w, double h) {
if(patch == null)
patch = new GrappaBox(x, y, w, h);
else
patch.setRect(x, y, w, h);
}
//
// End PatchWork stuff
//
}
att/grappa/ExceptionDisplay.java
att/grappa/ExceptionDisplay.java/*
* This software may only be used by you under license from AT&T Corp.
* (“AT&T”). A copy of AT&T’s Source Code Agreement is available at
* AT&T’s Internet website having the URL:
*
* If you received this software without first entering into a license
* with AT&T, you have an infringing copy of this software and cannot use
* it without violating AT&T’s intellectual property rights.
*/
package att.grappa;
import java.io.*;
import java.awt.*;
import java.awt.event.*;
/**
* A class for displaying exception information in a pop-up frame.
* As a convenience, an instance exists as a static member of
* the Grappa
class.
*
* @see Grappa#displayException(java.lang.Exception)
* @see Grappa#displayException(java.lang.Exception,java.lang.String)
*
* @version 1.2, 26 May 2005; Copyright 1996 – 2005 by AT&T Corp.
* @author John Mocenigo, Research @ AT&T Labs
*/
public class ExceptionDisplay {
private String title = null;
Exception exception = null;
Display display = null;
/**
* Creates an instance of the class for displaying exceptions.
*
* @param title the title for the pop-up frame
*/
public ExceptionDisplay(String title) {
this.title = title;
}
/**
* Pops up the frame and displays information on the supplied exception.
* Initially, a text area displays the message associated with the exception.
* By pressing a button, an end-user can view a stack trace as well.
*
* @param ex the exception about which informtaion is to be displayed.
*/
public void displayException(Exception ex) {
displayException(ex,null);
}
/**
* Pops up the frame and displays information on the supplied exception.
* Initially, a text area displays the supplied string followed on the
* next line by the message associated with the exception.
* By pressing a button, an end-user can view a stack trace as well.
*
* @param ex the exception about which informtaion is to be displayed.
*/
public void displayException(Exception ex, String msg) {
if(display == null) display = new Display(title);
exception = ex;
if(ex == null && msg == null) {
return;
}
if(msg != null) {
if(ex == null) {
display.setText(msg);
} else {
display.setText(msg + Grappa.NEW_LINE + ex.getMessage());
}
} else {
display.setText(ex.getMessage());
}
display.setVisible(true);
}
// TODO: re-do this using JFrame (not a big deal)
class Display extends Frame {
private TextArea textarea = null;
private Panel buttonPanel = null;
private Button trace = null;
private Button dismiss = null;
private WindowObserver observer = null;
Display(String title) {
super(title);
observer = new WindowObserver();
GridBagLayout gbl = new GridBagLayout();
GridBagConstraints gbc = new GridBagConstraints();
gbc.insets = new Insets(4,4,4,4);
gbc.weightx = 1;
gbc.weighty = 1;
gbc.gridwidth = GridBagConstraints.REMAINDER;
setLayout(gbl);
textarea = new TextArea(“”,7,80);
textarea.setEditable(false);
buttonPanel = new Panel();
buttonPanel.setLayout(new BorderLayout());
trace = new Button(“Stack Trace”);
trace.addActionListener(observer);
dismiss = new Button(“Dismiss”);
dismiss.addActionListener(observer);
buttonPanel.add(“West”,trace);
buttonPanel.add(“East”,dismiss);
gbc.fill = GridBagConstraints.BOTH;
gbl.setConstraints(textarea,gbc);
add(textarea);
gbc.weighty = 0;
gbc.fill = GridBagConstraints.HORIZONTAL;
gbl.setConstraints(buttonPanel,gbc);
add(buttonPanel);
addWindowListener(observer);
pack();
}
void setText(String text) {
if(text == null) text = “No message to display, try stack trace.”;
textarea.setText(text);
}
Exception getException() {
return exception;
}
class WindowObserver extends WindowAdapter implements ActionListener {
public void windowClosing(WindowEvent evt) {
dismiss();
}
private void dismiss() {
setVisible(false);
dispose();
display = null;
}
public void actionPerformed(ActionEvent evt) {
Object src = evt.getSource();
if(src instanceof Button) {
Button btn = (Button)src;
if(btn.getLabel().equals(“Dismiss”)) {
setVisible(false);
} else if(btn.getLabel().equals(“Stack Trace”)) {
if(getException() == null) {
setText(“No stack trace available (exception is null).”);
} else {
StringWriter swriter = new StringWriter();
PrintWriter pwriter = new PrintWriter(swriter);
getException().printStackTrace(pwriter);
pwriter.flush();
setText(swriter.toString());
pwriter.close();
}
}
}
}
}
}
}
att/grappa/Graph.java
att/grappa/Graph.java/*
* This software may only be used by you under license from AT&T Corp.
* (“AT&T”). A copy of AT&T’s Source Code Agreement is available at
* AT&T’s Internet website having the URL:
*
* If you received this software without first entering into a license
* with AT&T, you have an infringing copy of this software and cannot use
* it without violating AT&T’s intellectual property rights.
*/
package att.grappa;
import java.util.*;
import java.io.*;
/**
* This class is the root of the overall graph and provides methods for
* working with the entire graph (for example. printing the graph). It is an
* extension of the Subgraph class.
*
* @version 1.2, 26 May 2005; Copyright 1996 – 2005 by AT&T Corp.
* @author John Mocenigo, Research @ AT&T Labs
*/
public class Graph extends Subgraph
{
/**
* The string used for indentation when printing out the graph.
*/
public final static String INDENT_STRING = ” “;
/**
* used internally by Grappa
*/
boolean filterMode = false;
// used with getIndent, incrementIndent and decrementIndent
private StringBuffer indent = null;
// used for error message (when set by setErrorWriter)
private PrintWriter errWriter = null;
// for keeping track of paint calls
private boolean paintCalled = false;
// for indicating if graph is busy being painted or altered
private boolean busy = false;
// for indicating if synchronization (involving the above) should be used
private boolean synchronizePaint = false;
//private UndoStack undoStack = new UndoStack();
//private EditOp lastUndo = null;
// graph-specific outside-the-bounds tooltip text
private String toolTipText = null;
// list of panels displaying this graph
private List panelList = null;
// counters for subgraph, node and edge elements (for id generation)
private int gid = 0;
private int nid = 0;
private int eid = 0;
// indicators for properties of the graph
private boolean editable = false;
private boolean menuable = false;
private boolean selectable = true;
// not used yet
// public boolean autoUpdate = false; // TODO: add thread, etc.
// directed graph?
private boolean directed = true;
// strict graph?
private boolean strict = false;
// for mapping id to an element
Hashtable id2element = null;
// Grappa global attributes (apply to all elements)
private Hashtable grattributes = null;
// tables for graph default node, edge and graph attributes, which are
// initialized below
private static Hashtable sysdfltNodeAttributes = new Hashtable(8);
private static Hashtable sysdfltEdgeAttributes = new Hashtable(7);
private static Hashtable sysdfltGraphAttributes = new Hashtable(11);
// graph default node, edge and graph attributes, these should be
// consistent with the dot layout program, although it is not necessary.
static {
// node
putAttribute(sysdfltNodeAttributes,NODE,COLOR_ATTR,”black”);
putAttribute(sysdfltNodeAttributes,NODE,FONTCOLOR_ATTR,”black”);
putAttribute(sysdfltNodeAttributes,NODE,FONTNAME_ATTR,”TimesRoman”);
putAttribute(sysdfltNodeAttributes,NODE,FONTSIZE_ATTR,”14″);
putAttribute(sysdfltNodeAttributes,NODE,FONTSTYLE_ATTR,”normal”);
putAttribute(sysdfltNodeAttributes,NODE,HEIGHT_ATTR,”0.5″);
putAttribute(sysdfltNodeAttributes,NODE,POS_ATTR,”0,0″);
putAttribute(sysdfltNodeAttributes,NODE,LABEL_ATTR,”\\N”);
putAttribute(sysdfltNodeAttributes,NODE,SHAPE_ATTR,”ellipse”);
putAttribute(sysdfltNodeAttributes,NODE,STYLE_ATTR,GrappaStyle.DEFAULT_SET_STRING);
putAttribute(sysdfltNodeAttributes,NODE,WIDTH_ATTR,”0.75″);
// edge
putAttribute(sysdfltEdgeAttributes,EDGE,COLOR_ATTR,”black”);
putAttribute(sysdfltEdgeAttributes,EDGE,DIR_ATTR,”forward”);
putAttribute(sysdfltEdgeAttributes,EDGE,FONTCOLOR_ATTR,”black”);
putAttribute(sysdfltEdgeAttributes,EDGE,FONTNAME_ATTR,”TimesRoman”);
putAttribute(sysdfltEdgeAttributes,EDGE,FONTSIZE_ATTR,”14″);
putAttribute(sysdfltEdgeAttributes,EDGE,FONTSTYLE_ATTR,”normal”);
putAttribute(sysdfltEdgeAttributes,EDGE,MINLEN_ATTR,”1″);
putAttribute(sysdfltEdgeAttributes,EDGE,STYLE_ATTR,GrappaStyle.DEFAULT_SET_STRING);
putAttribute(sysdfltEdgeAttributes,EDGE,WEIGHT_ATTR,”1″);
// graph
putAttribute(sysdfltGraphAttributes,SUBGRAPH,CLUSTERRANK_ATTR,”local”);
putAttribute(sysdfltGraphAttributes,SUBGRAPH,COLOR_ATTR,”white”);
putAttribute(sysdfltGraphAttributes,SUBGRAPH,FONTCOLOR_ATTR,”black”);
putAttribute(sysdfltGraphAttributes,SUBGRAPH,FONTNAME_ATTR,”TimesRoman”);
putAttribute(sysdfltGraphAttributes,SUBGRAPH,FONTSIZE_ATTR,”14″);
putAttribute(sysdfltGraphAttributes,SUBGRAPH,FONTSTYLE_ATTR,”normal”);
putAttribute(sysdfltGraphAttributes,SUBGRAPH,MARGIN_ATTR,”0.5,0.5″);
putAttribute(sysdfltGraphAttributes,SUBGRAPH,MCLIMIT_ATTR,”1″);
putAttribute(sysdfltGraphAttributes,SUBGRAPH,NODESEP_ATTR,”0.25″);
putAttribute(sysdfltGraphAttributes,SUBGRAPH,ORIENTATION_ATTR,”portrait”);
putAttribute(sysdfltGraphAttributes,SUBGRAPH,RANKDIR_ATTR,”TB”);
putAttribute(sysdfltGraphAttributes,SUBGRAPH,RANKSEP_ATTR,”0.75″);
putAttribute(sysdfltGraphAttributes,SUBGRAPH,STYLE_ATTR,GrappaStyle.DEFAULT_SET_STRING);
}
// used for the above static initialization
private static void putAttribute(Hashtable table, int type, String name, String value) {
Attribute attr = new Attribute(type,name,value);
attr.clearChanged();
table.put(name,attr);
}
/**
* Reference FontRenderContext
*/
public final java.awt.font.FontRenderContext REFCNTXT = new java.awt.font.FontRenderContext(IDENTXFRM, Grappa.useAntiAliasing, Grappa.useFractionalMetrics);
/**
* Creates a new, empty Graph object.
*
* @param graphName the name of this graph.
* @param directed use true if graph is to be a directed graph
* @param strict use true if graph is a strict graph
*/
public Graph(String graphName, boolean directed, boolean strict) {
//super();
initialize(graphName);
setDirection(directed);
this.strict = strict;
// grappa attributes used for drawing
setGrappaAttribute(GRAPPA_BACKGROUND_COLOR_ATTR,”white”);
setGrappaAttribute(GRAPPA_SELECTION_STYLE_ATTR,”lineColor(red),lineWidth(3)”);
setGrappaAttribute(GRAPPA_DELETION_STYLE_ATTR,”lineColor(grey85),lineWidth(3),dotted”);
setGrappaAttribute(GRAPPA_FONTSIZE_ADJUSTMENT_ATTR,”0″);
}
/**
* Creates a directed graph that is not strict
* A convenience method equivalent to Graph(graphName,true,false).
*
* @param graphName the name of this graph.
* @see Graph#Graph(java.lang.String, boolean, boolean)
*/
public Graph(String graphName) {
this(graphName,true,false);
}
// graph initialization steps
private void initialize(String graphName) {
eid = nid = gid = 0;
clearBBox();
if(id2element != null) {
id2element.clear();
}
setGraph(this);
setSubgraph(null);
setIdKey(Grappa.SUBGRAPH);
addIdMapping(this);
setName(graphName);
Attribute attr = null;
Enumeration enm = getGlobalAttributePairs(Grappa.NODE);
while(enm.hasMoreElements()) {
setNodeAttribute((Attribute)enm.nextElement());
}
enm = getGlobalAttributePairs(Grappa.EDGE);
while(enm.hasMoreElements()) {
setEdgeAttribute((Attribute)enm.nextElement());
}
enm = getGlobalAttributePairs(Grappa.SUBGRAPH);
while(enm.hasMoreElements()) {
setAttribute((Attribute)enm.nextElement());
}
setDelete(false);
}
private void setDirection(boolean directed) {
this.directed = directed;
if(directed) {
setEdgeAttribute(DIR_ATTR, “forward”);
} else {
setEdgeAttribute(DIR_ATTR, “none”);
}
}
/**
* Sets or unsets indication that paint requests should be done
* within a synchronized wrapper that prevents concurrent paints
* and any paints between calls to the dropcloth method.
*
* @param sync value to which indicator will be set
* @return the previous indicator value
* @see Graph#dropcloth(boolean, boolean)
*/
public boolean setSynchronizePaint(boolean sync) {
boolean oldSync = synchronizePaint;
synchronizePaint = sync;
return(oldSync);
}
/**
* Get the current paint synchronization indicator value.
*
* @return the current paint synchronization indicator value
* @see Graph#setSynchronizePaint(boolean)
*/
public boolean getSynchronizePaint() {
return(synchronizePaint);
}
/**
* Sets and unsets a flag in a synchronized manner so that during the
* period that the flag is set, painting will not occur.
*
* @param block value to which to set the indicator flag
* @param auto when block is false, setting this parameter true will request a repaint() if any paint requests arrived while the dropcloth was laid out.
* @return returns false only when block is true and a paint is pending or in progress.
* @see Graph#setSynchronizePaint(boolean)
*
*/
public boolean dropcloth(boolean block, boolean auto) {
return setBlocked(block, false, auto);
}
// used in GrappaPanel
boolean setPaint(boolean paint) {
return setBlocked(paint, true, false);
}
private synchronized boolean setBlocked(boolean state, boolean isPaint, boolean repaint) {
if(isPaint) {
if(state) {
paintCalled = true;
if(busy) {
return(false);
} else {
return(busy = true);
}
} else {
paintCalled = busy = false;
return(true);
}
} else if(state) {
if(paintCalled) return(false);
return(busy = true);
} else {
if(!paintCalled) {
busy = false;
} else {
busy = paintCalled = false;
if(repaint) repaint();
}
return(true);
}
}
/**
* Gets Grappa default attribute.
*
* @param key the search key for the corresponding attribute.
* @exception IllegalArgumentException whenever the key is null
* @return the value of the matching Grappa default attribute or null.
*/
public Attribute getGrappaAttribute(String key) throws IllegalArgumentException {
if(key == null) {
throw new IllegalArgumentException(“key value cannot be null”);
}
if(grattributes == null) return null;
return ((Attribute)(grattributes.get(key)));
}
/**
* Gets Grappa default attribute value.
*
* @param key the search key for the corresponding attribute.
* @exception IllegalArgumentException whenever the key is null
* @return the value portion of the matching Grappa default attribute or null.
*/
public Object getGrappaAttributeValue(String key) throws IllegalArgumentException {
if(key == null) {
throw new IllegalArgumentException(“key value cannot be null”);
}
if(grattributes == null) return null;
Attribute attr = (Attribute)(grattributes.get(key));
if(attr == null) return null;
return(attr.getValue());
}
/**
* Sets a Grappa package attribute. A Grappa package attribute is one
* specific to Grappa (for example, a display color) rather than an
* attribute that relates to a graph.
*
* @param key the search key for the corresponding attribute.
* @exception IllegalArgumentException whenever the key is not prefixed by Grappa.PKG_LOWER
* @return the previous value of the matching Grappa default attribute or null.
* @see GrappaConstants#PKG_LOWER
*/
public Object setGrappaAttribute(String key, String value) throws IllegalArgumentException {
if(grattributes == null) {
grattributes = new Hashtable(4);
}
// the get also tests if key is null
Attribute oldValue = getGrappaAttribute(key);
if(oldValue == null) {
if(!validGrappaAttributeKey(key)) {
throw new IllegalArgumentException(Grappa.PKG_UPLOW + ” attribute key must use \”” + Grappa.PKG_LOWER + “\” as a prefix”);
}
oldValue = new Attribute(SYSTEM,key,value);
grattributes.put(key,oldValue);
return null;
} else {
grattributes.put(key, new Attribute(SYSTEM,key,value));
}
return oldValue.getValue();
}
/**
* Returns the attribute conversion type for the supplied attribute name.
* Only graph global specific attribute name/type mappings are checked.
*
* @param attrname the attribute name
* @return the currently associated attribute type
*/
public static int attributeType(String attrname) {
int convtype = -1;
int hashCode;
if(attrname != null) {
hashCode = attrname.hashCode();
if(hashCode == GRAPPA_BACKGROUND_COLOR_HASH && attrname.equals(GRAPPA_BACKGROUND_COLOR_ATTR)) {
convtype = COLOR_TYPE;
} else if(hashCode == GRAPPA_SELECTION_STYLE_HASH && attrname.equals(GRAPPA_SELECTION_STYLE_ATTR)) {
convtype = STYLE_TYPE;
} else if(hashCode == GRAPPA_DELETION_STYLE_HASH && attrname.equals(GRAPPA_DELETION_STYLE_ATTR)) {
convtype = STYLE_TYPE;
} else if(hashCode == GRAPPA_FONTSIZE_ADJUSTMENT_HASH && attrname.equals(GRAPPA_FONTSIZE_ADJUSTMENT_ATTR)) {
convtype = INTEGER_TYPE;
} else {
convtype = STRING_TYPE;
}
}
return(convtype);
}
/**
* Get an enumeration of the Grappa package attribute keys.
*
* @return an Enumeration of Attribute objects
*/
public Enumeration getGrappaAttributeKeys() {
if(grattributes == null) {
return Grappa.emptyEnumeration.elements();
}
return grattributes.keys();
}
/**
* Check if the given key has a format consistent with Grappa package
* attribute keys. A Grappa package key starts with Grappa.PKG_LOWER.
*
* @param key the key to validate
* @return true if the supplied key could serve as a Grappa package attribute key.
* @see GrappaConstants#PKG_LOWER
*/
public static boolean validGrappaAttributeKey(String key) {
return (key != null && key.startsWith(Grappa.PKG_LOWER) && key.length() > Grappa.PKG_LOWER.length());
}
/**
* Gets a graph default attribute. A graph default attribute determines
* basic graph characteristics initially (e.g., node shape).
*
* @param type indicates attribute type.
* @param key the search key for the corresponding attribute.
* @exception IllegalArgumentException whenever the specified type is not valid
* @return the value of the matching graph default attribute or null.
* @see GrappaConstants#NODE
* @see GrappaConstants#EDGE
* @see GrappaConstants#SUBGRAPH
*/
public static Attribute getGlobalAttribute(int type, String key) throws IllegalArgumentException {
switch(type) {
case Grappa.NODE:
return((Attribute)sysdfltNodeAttributes.get(key));
case Grappa.EDGE:
return((Attribute)sysdfltEdgeAttributes.get(key));
case Grappa.SUBGRAPH:
return((Attribute)sysdfltGraphAttributes.get(key));
}
throw new IllegalArgumentException(“specified type must be NODE, EDGE or SUBGRAPH”);
}
/**
* Gets an enumeration of the specified graph default attribute keys
*
* @param type indicates attribute type.
* @exception IllegalArgumentException whenever the specified type is not valid
* @return an Enumeration of String objects
* @see GrappaConstants#NODE
* @see GrappaConstants#EDGE
* @see GrappaConstants#SUBGRAPH
*/
public static Enumeration getGlobalAttributeKeys(int type) throws IllegalArgumentException {
switch(type) {
case Grappa.NODE:
return(sysdfltNodeAttributes.keys());
case Grappa.EDGE:
return(sysdfltEdgeAttributes.keys());
case Grappa.SUBGRAPH:
return(sysdfltGraphAttributes.keys());
}
throw new IllegalArgumentException(“specified type must be NODE, EDGE or SUBGRAPH”);
}
/**
* Gets an enumeration of the specified graph default attributes
*
* @param type indicates attribute type.
* @exception IllegalArgumentException whenever the specified type is not valid
* @return an Enumeration of Attribute objects
* @see GrappaConstants#NODE
* @see GrappaConstants#EDGE
* @see GrappaConstants#SUBGRAPH
*/
public static Enumeration getGlobalAttributePairs(int type) throws IllegalArgumentException {
switch(type) {
case Grappa.NODE:
return(sysdfltNodeAttributes.elements());
case Grappa.EDGE:
return(sysdfltEdgeAttributes.elements());
case Grappa.SUBGRAPH:
return(sysdfltGraphAttributes.elements());
}
throw new IllegalArgumentException(“specified type must be NODE, EDGE or SUBGRAPH”);
}
/**
* Get a count of the graph default attributes of a particular type.
*
* @param type indicates attribute type.
* @exception IllegalArgumentException whenever the specified type is not valid
* @return a count of the specified graph default attributes
* @see GrappaConstants#NODE
* @see GrappaConstants#EDGE
* @see GrappaConstants#SUBGRAPH
*/
public static int getGlobalAttributeSize(int type) throws IllegalArgumentException {
switch(type) {
case Grappa.NODE:
return(sysdfltNodeAttributes.size());
case Grappa.EDGE:
return(sysdfltEdgeAttributes.size());
case Grappa.SUBGRAPH:
return(sysdfltGraphAttributes.size());
}
throw new IllegalArgumentException(“specified type must be NODE, EDGE or SUBGRAPH”);
}
/**
* Add id to element lookup table
* (used in setId method)
*
* @param elem the element associated with the id
*/
Element addIdMapping(Element elem) {
if(elem == null) {
return null;
}
if(id2element == null) {
id2element = new Hashtable();
}
return (Element)id2element.put(elem.getIdKey(),elem);
}
/**
* Creates a id key given a type and id number.
*
* @param type one of Grappa.NODE, Grappa.EDGE or Grappa.SUBGRAPH
* @param id an id number
* @exception IllegalArgumentException whenever the specified type is not valid
* @return an idKey for an element
* @see GrappaConstants#NODE
* @see GrappaConstants#EDGE
* @see GrappaConstants#SUBGRAPH
*/
static Long idMapKey(int type, int id) throws IllegalArgumentException {
long value = (long)(id);
int tval = (type&(Grappa.NODE|Grappa.EDGE|Grappa.SUBGRAPH));
if(tval == 0) {
throw new IllegalArgumentException(“supplied type does not specify node, edge or subgraph”);
}
value = (value << Grappa.TYPES_SHIFT) | (type&(Grappa.NODE|Grappa.EDGE|Grappa.SUBGRAPH));
return new Long(value);
}
/**
* Get the type of the id key.
*
* @param idKey the id key to examine
* @return the type of the id key (Grappa.NODE, Grappa.EDGE, Grappa.SUBGRAPH)
* @see GrappaConstants#NODE
* @see GrappaConstants#EDGE
* @see GrappaConstants#SUBGRAPH
*/
static int idKeyType(Long idKey) {
long value = idKey.longValue();
return (int)(value&(Grappa.NODE|Grappa.EDGE|Grappa.SUBGRAPH));
}
/**
* Get the type of the id key.
*
* @param idKey the id key to examine
* @return the type of the id key (Grappa.NODE, Grappa.EDGE, Grappa.SUBGRAPH)
* @see GrappaConstants#NODE
* @see GrappaConstants#EDGE
* @see GrappaConstants#SUBGRAPH
*/
static int idKeyId(Long idKey) {
long value = idKey.longValue();
return (int)(value>>>Grappa.TYPES_SHIFT);
}
/**
* Get the element associated with an id key
*
* @param idKey the id key of the element to be located
* @return the Element object matching the id key or null
*/
Element element4Id(Long idKey) {
if(id2element == null) {
return null;
}
return (Element)id2element.get(idKey);
}
/**
* Remove id2element dictionary element
*
* @param id the id number of the element entry to be removed
*/
void removeIdMapping(Element elem) {
if(id2element != null && elem != null) {
id2element.remove(elem.getIdKey());
}
}
/**
* Output graph to specified Writer.
*
* @param output the Writer for writing
*/
public void printGraph(Writer output) {
PrintWriter out = null;
if(output instanceof PrintWriter) {
out = (PrintWriter)output;
} else {
out = new PrintWriter(output);
}
getGraph().printSubgraph(out);
out.flush();
}
/**
* Output graph to specified OutputStream.
* A convenience method to accomodate the OuputStreams easily.
*
* @param output the OutputStream for writing
*/
public void printGraph(OutputStream output) {
printGraph(new PrintWriter(output));
}
/**
* Get the next id number for the specified type and increment the counter.
*
* @param type type of id number to return
* @exception IllegalArgumentException whenever the specified type is not valid
* @return the next sequential id number (counter is incremented).
* @see GrappaConstants#NODE
* @see GrappaConstants#EDGE
* @see GrappaConstants#SUBGRAPH
*/
int nextId(int type) throws IllegalArgumentException {
switch(type) {
case Grappa.NODE:
return(nid++);
case Grappa.EDGE:
return(eid++);
case Grappa.SUBGRAPH:
return(gid++);
}
throw new IllegalArgumentException(“Type (“+type+”) is not recognized.”);
}
/**
* Get the next id number for the specified type, but do not increment the counter.
*
* @param type type of id number to return
* @exception IllegalArgumentException whenever the specified type is not valid
* @return the next sequential id number (counter is not incremented).
* @see GrappaConstants#NODE
* @see GrappaConstants#EDGE
* @see GrappaConstants#SUBGRAPH
*/
public int getId(int type) throws IllegalArgumentException {
switch(type) {
case Grappa.NODE:
return(nid);
case Grappa.EDGE:
return(eid);
case Grappa.SUBGRAPH:
return(gid);
}
throw new IllegalArgumentException(“Type (“+type+”) is not recognized.”);
}
/**
* Get the current indent string.
*
* @return the current indent string.
*/
public String getIndent() {
if(indent == null) {
indent = new StringBuffer(5 * INDENT_STRING.length());
}
return(indent.toString());
}
/**
* Increase the indent string by appending INDENT_STRING.
*
* @see Graph#INDENT_STRING
*/
public void incrementIndent() {
if(indent == null) {
indent = new StringBuffer(5 * INDENT_STRING.length());
}
indent.append(INDENT_STRING);
}
/**
* Decrease the indent string by removing one INDENT_STRING.
*
* @see Graph#INDENT_STRING
*/
public void decrementIndent() {
int len = indent.length();
if(len == 0) return;
if(len < INDENT_STRING.length()) {
indent.setLength(0);
} else {
indent.setLength(len - INDENT_STRING.length());
}
}
/**
* Check if the graph is directed.
*
* @return true if graph is a directed graph
*/
public boolean isDirected() {
return(directed);
}
/**
* Check if the graph is strict (i.e., no self-loops).
*
* @return true if the graph is strict
*/
public boolean isStrict() {
return(strict);
}
/**
* Set the tooltip text displayed when outside the graph area.
*
* @param text out-of-graph tooltip text
* @return previous out-of-graph tooltip text
*/
public String setToolTipText(String text) {
String oldTip = toolTipText;
toolTipText = text;
return(oldTip);
}
/**
* Get the tooltip text displayed when outside the graph area.
*
* @return out-of-graph tooltip text
*/
public String getToolTipText() {
return(toolTipText);
}
//TODO find out dot options to fill or outline graph also orientation.
/**
* Reset this graph by removing all its elements and re-initiailizing
* its internal variables.
*/
public void reset() {
String graphName = getName();
if(delete()) initialize(graphName);
}
/**
* Reset this graph by removing all its elements and re-initiailizing
* its internal variables and possibly changing its name, directedness
* and strictness.
*/
public void reset(String graphName, boolean directed, boolean strict) {
name = graphName;
reset();
setDirection(directed);
this.strict = strict;
}
/**
* Check if this graph is interactively editable (i.e., through mouse events).
*
* @return true if the graph can be edited interactively.
*/
public boolean isEditable() {
return editable;
}
/**
* Set the editability of the graph.
*
* @param mode true to turn on editability.
* @return previous value
* @see Graph#isEditable()
*/
public boolean setEditable(boolean mode) {
boolean wasMode = editable;
editable = mode;
return wasMode;
}
/**
* Check if graph elements are interactively selectable (i.e., through mouse events).
*
* @return true if graph elements can be selected interactively.
*/
public boolean isSelectable() {
return selectable;
}
/**
* Set the selectability of the graph.
*
* @param mode true to turn on selectability.
* @return previous value
* @see Graph#isSelectable()
*/
public boolean setSelectable(boolean mode) {
boolean wasMode = selectable;
selectable = mode;
return wasMode;
}
/**
* Check if an element-specific menu is available interactively (i.e., through mouse events).
*
* @return true if an element-specific menu is available
*/
public boolean isMenuable() {
return menuable;
}
/**
* Set whether element-specific menus are to be available interactively.
*
* @param mode true to turn on element-specific-menus.
* @return previous value
* @see Graph#isMenuable()
*/
public boolean setMenuable(boolean mode) {
boolean wasMode = menuable;
menuable = mode;
return wasMode;
}
/**
* Set the PrintWriter for error messages.
*
* @param errWriter the PrintWriter to use for error messages.
* @return the previous PrintWriter used for error messages.
* @see java.io.PrintWriter
*/
public PrintWriter setErrorWriter(PrintWriter errWriter) {
PrintWriter oldWriter = this.errWriter;
this.errWriter = errWriter;
return oldWriter;
}
/**
* Get the current PrintWriter used for error messages.
*
* @return the current PrintWriter used for error messages.
* @see java.io.PrintWriter
*/
public PrintWriter getErrorWriter() {
return errWriter;
}
/**
* Print the supplied message to the error output.
* Nothing happens if the error output is set to null.
*
* @param msg the message to print on the error output.
* @see Graph#setErrorWriter(java.io.PrintWriter)
*/
public void printError(String msg) {
printError(msg,null);
}
/**
* Print the supplied message and exception information to the error output.
* Nothing happens if the error output is set to null.
*
* @param msg the message to print on the error output.
* @param ex if supplied, the stack trace associated with this exception is also printed.
* @see Graph#setErrorWriter(java.io.PrintWriter)
*/
public void printError(String msg, Exception ex) {
if(getErrorWriter() == null) return;
getErrorWriter().println("ERROR: " + msg);
if(ex != null) ex.printStackTrace(getErrorWriter());
getErrorWriter().flush();
}
//////////////////////////////////////////////////////////////////////
/**
* Builds any GrappaNexus object not already built for elements in
* this graph.
*/
public void buildShapes() {
GraphEnumeration enm = elements();
Element elem;
while(enm.hasMoreElements()) {
elem = enm.nextGraphElement();
if(elem.grappaNexus == null) {
elem.buildShape();
}
}
}
/**
* Builds any GrappaNexus object not already built and rebuilds those
* that already exist for all elements in this graph.
*/
public void resync() {
Element elem = null;
GraphEnumeration enm = elements();
while(enm.hasMoreElements()) {
elem = enm.nextGraphElement();
if(elem.grappaNexus == null) elem.buildShape();
else elem.grappaNexus.rebuild();
}
}
//////////////////////////////////////////////////////////////////////
/**
* Makes a repaint request of all GrappaPanels that are displaying
* this graph.
*/
public void repaint() {
if(panelList == null) return;
boolean incomplete = true;
ListIterator li = null;
while(incomplete) {
try {
li = panelList.listIterator(0);
while(li.hasNext()) {
((GrappaPanel)li.next()).repaint();
}
} catch(ConcurrentModificationException cme) {
continue;
}
incomplete = false;
}
}
/**
* Makes a paintImmediately request of all GrappaPanels that are displaying
* this graph.
*/
public void paintImmediately() {
if(panelList == null) return;
boolean incomplete = true;
ListIterator li = null;
GrappaPanel panel = null;
while(incomplete) {
try {
li = panelList.listIterator(0);
while(li.hasNext()) {
panel = ((GrappaPanel)li.next());
panel.paintImmediately(panel.getVisibleRect());
}
} catch(ConcurrentModificationException cme) {
continue;
}
incomplete = false;
}
}
/**
* Adds a panel to the list of GrappaPanels that are displaying
* this graph.
*
* @param panel the GrappaPanel to be added to the list
*/
public void addPanel(GrappaPanel panel) {
if(panelList == null) {
panelList = Collections.synchronizedList(new LinkedList());
}
synchronized(panelList) {
if(!panelList.contains(panel)) panelList.add(panel);
}
}
/**
* Removes a panel to the list of GrappaPanels that are displaying
* this graph.
*
* @param panel the GrappaPanel to be removed to the list
*/
public void removePanel(GrappaPanel panel) {
if(panelList == null) return;
synchronized(panelList) {
panelList.remove(panel);
}
}
}
att/grappa/GraphEnumeration.java
att/grappa/GraphEnumeration.java/*
* This software may only be used by you under license from AT&T Corp.
* ("AT&T"). A copy of AT&T's Source Code Agreement is available at
* AT&T's Internet website having the URL:
*
* If you received this software without first entering into a license
* with AT&T, you have an infringing copy of this software and cannot use
* it without violating AT&T’s intellectual property rights.
*/
package att.grappa;
/**
* An extension of the Enumeration interface specific to enumerations of
* graph elements.
*
* @version 1.2, 26 May 2005; Copyright 1996 – 2005 by AT&T Corp.
* @author John Mocenigo, Research @ AT&T Labs
*/
public interface GraphEnumeration extends java.util.Enumeration
{
/**
* Get the root of this enumeration.
*
* @return the root subgraph for this enumeration
*/
public Subgraph getSubgraphRoot();
/**
* Get the types of elements possibly contained in this enumeration.
*
* @return an indication of the types of elements in this enumeration
* @see GrappaConstants#NODE
* @see GrappaConstants#EDGE
* @see GrappaConstants#SUBGRAPH
*/
public int getEnumerationTypes();
/**
* A convenience method that should just return a cast
* of a call to nextElement()
*
* @return the next graph element in the enumeration
* @exception java.util.NoSuchElementException whenever the enumeration has no more
* elements.
*/
public Element nextGraphElement() throws java.util.NoSuchElementException;
}
att/grappa/GraphParserException.java
att/grappa/GraphParserException.java/*
* This software may only be used by you under license from AT&T Corp.
* (“AT&T”). A copy of AT&T’s Source Code Agreement is available at
* AT&T’s Internet website having the URL:
*
* If you received this software without first entering into a license
* with AT&T, you have an infringing copy of this software and cannot use
* it without violating AT&T’s intellectual property rights.
*/
package att.grappa;
/**
* This class is used whenever a problem is detected during parsing.
*
* @version 1.2, 26 May 2005; Copyright 1996 – 2005 by AT&T Corp.
* @author John Mocenigo, Research @ AT&T Labs
*/
public class GraphParserException extends RuntimeException
{
/**
* Constructs an GraphParserException
with no detail message.
*/
public GraphParserException() {}
/**
* Constructs an GraphParserException
with the specified
* detail message.
*
* @param message the detail message.
*/
public GraphParserException(String message) {
super(message);
}
}
att/grappa/Grappa.java
att/grappa/Grappa.java/*
* This software may only be used by you under license from AT&T Corp.
* (“AT&T”). A copy of AT&T’s Source Code Agreement is available at
* AT&T’s Internet website having the URL:
*
* If you received this software without first entering into a license
* with AT&T, you have an infringing copy of this software and cannot use
* it without violating AT&T’s intellectual property rights.
*/
package att.grappa;
/**
* This class sets default option variables and other set-up.
* In addition, some convenience methods for exception display are
* included and some lookup tables are initialized.
*
*
The Grappa package itself has two roles:
- building, maintaining and manipulating graph structure, and
* - drawing a positioned graph.
*
* Grappa itself does not have any methods for graph positioning.
* Grappa simply draws the nodes and edges based on the value of the
* element’s pos attribute, though it will treat an unpositioned
* edge as a straight line between the center points of its attached nodes.
*
* Some graph layout references are:
- “An Algorithm for Drawing General Undirected Graphs”,
* Tomihisa Kamada and Satoru Kawai,
* Information Processing Letters, Vol. 31 (1989), pp. 7 – 15
*
* - “Graph Drawing by Force-directed Placement”,
* Thomas M. J. Fruchterman and Edward M. Reingold,
* Software – Practice and Experience, Vol. 21 No. 11 (1991), pp. 1129 – 1164
*
* - “A Technique for Drawing Directed Graphs”,
* Emden R. Gansner, Eleftherios Koutsofios, Stephen C. North and
* Kiem-Phong Vo,
* IEEE Transactions on Software Engineering, Vol 19 No. 3 (1993), pp. 214 – 230
*
* - “NicheWorks – Interactive Visualization of Very Large Graphs”,
* Graham J. Wills,
* http://www.bell-labs.com:80/user/gwills/NICHEguide/nichepaper.html, circa 1997
*
*
*
Grappa does supply a utility, GrappaSupport.filterGraph(), for updating
* a graph (including position information) from I/O streams such as might
* be obtained from a java.net.URLConnection.
*
* @version 1.2, 26 May 2005; Copyright 1996 – 2005 by AT&T Corp.
* @author John Mocenigo, Research @ AT&T Labs
*/
public abstract class Grappa
implements att.grappa.GrappaConstants
{
/**
* Look-up table that maps a shape name to its integer reference value.
*/
public static java.util.Hashtable keyToShape = new java.util.Hashtable();
/**
* Look-up table that maps a shape reference value to its name.
*/
public static java.util.Hashtable shapeToKey = new java.util.Hashtable();
/*
* Set-up lookup table that defines recognized shapes (useful
* for switch statements).
*/
static {
keyToShape.put(“box”, new Integer(BOX_SHAPE));
keyToShape.put(“circle”, new Integer(OVAL_SHAPE));
keyToShape.put(“custom”, new Integer(CUSTOM_SHAPE));
keyToShape.put(“diamond”, new Integer(DIAMOND_SHAPE));
keyToShape.put(“doublecircle”, new Integer(DOUBLECIRCLE_SHAPE));
keyToShape.put(“doubleoctagon”, new Integer(DOUBLEOCTAGON_SHAPE));
keyToShape.put(“egg”, new Integer(EGG_SHAPE));
keyToShape.put(“ellipse”, new Integer(OVAL_SHAPE));
keyToShape.put(“hexagon”, new Integer(HEXAGON_SHAPE));
keyToShape.put(“house”, new Integer(HOUSE_SHAPE));
keyToShape.put(“invhouse”, new Integer(INVERTEDHOUSE_SHAPE));
keyToShape.put(“invtrapezium”, new Integer(INVERTEDTRAPEZIUM_SHAPE));
keyToShape.put(“invtriangle”, new Integer(INVERTEDTRIANGLE_SHAPE));
keyToShape.put(“octagon”, new Integer(OCTAGON_SHAPE));
keyToShape.put(“pentagon”, new Integer(PENTAGON_SHAPE));
keyToShape.put(“parallelogram”, new Integer(PARALLELOGRAM_SHAPE));
keyToShape.put(“plaintext”, new Integer(PLAINTEXT_SHAPE));
keyToShape.put(“point”, new Integer(POINT_SHAPE));
keyToShape.put(“polygon”, new Integer(POLYGON_SHAPE));
keyToShape.put(“record”, new Integer(RECORD_SHAPE));
keyToShape.put(“roundedbox”, new Integer(ROUNDEDBOX_SHAPE));
keyToShape.put(“trapezium”, new Integer(TRAPEZIUM_SHAPE));
keyToShape.put(“triangle”, new Integer(TRIANGLE_SHAPE));
keyToShape.put(“tripleoctagon”, new Integer(TRIPLEOCTAGON_SHAPE));
keyToShape.put(“Mcircle”, new Integer(MCIRCLE_SHAPE));
keyToShape.put(“Mdiamond”, new Integer(MDIAMOND_SHAPE));
keyToShape.put(“Mrecord”, new Integer(MRECORD_SHAPE));
keyToShape.put(“Msquare”, new Integer(MSQUARE_SHAPE));
java.util.Enumeration enm = keyToShape.keys();
String key = null;
while(enm.hasMoreElements()) {
key = (String)enm.nextElement();
shapeToKey.put(keyToShape.get(key),key);
}
// special case, but don’t want it in shapeToKey
keyToShape.put(“square”, new Integer(BOX_SHAPE));
}
/**
* The java.awt.Toolkit.getDefaultToolkit() value, if available
*/
public static java.awt.Toolkit toolkit = null;
static {
try {
toolkit = java.awt.Toolkit.getDefaultToolkit();
}
catch(java.awt.AWTError err) {
}
}
/*
* A instance of ExceptionDisplay used with the (public) convenience
* methods that follow.
*/
private static final ExceptionDisplay exceptionDisplay = new ExceptionDisplay(Grappa.PKG_UPLOW + “: Exception Detected”);
/**
* Boolean for enabling/disabling exception pop-up window display.
*/
public static boolean doDisplayException = true;
/**
* Method for displaying an exception in a pop-up window (if enabled).
* @param ex The exception value about which information is to be displayed.
* @see Grappa#doDisplayException
* @see DisplayException
*/
public static void displayException(java.lang.Exception ex) {
if(doDisplayException) exceptionDisplay.displayException(ex);
}
/**
* Method for displaying an exception in a pop-up window (if enabled).
* @param ex The exception value about which information is to be displayed.
* @param msg Additional text to be displayed ahead of exception info.
* @see Grappa#doDisplayException
* @see DisplayException
*/
public static void displayException(java.lang.Exception ex, java.lang.String msg) {
if(doDisplayException) exceptionDisplay.displayException(ex,msg);
}
/**
* A convenience Vector useful when an enumeration is to be returned, but
* the object to be enumerated is null (in which case, the return value can
* be Grappa.emptyEnumeration.elements(), whose hasMoreElements() method
* will return false).
*/
public static final java.util.Vector emptyEnumeration = new java.util.Vector(0,0);
/*
* Default tool-tip text when cursor is outside graph, but inside
* the display panel.
*/
private static String toolTipText = “
/**
* Sets the tool-tip text displayed when outside graph, but inside
* the display panel.
*
* @param text The new outside-the-graph tool-tip text to display.
*
* @return The former outside-the-graph tool-tip text.
*/
public static String setToolTipText(String text) {
String oldTip = toolTipText;
toolTipText = text;
return(oldTip);
}
/**
* Gets the current tool-tip text displayed when outside graph, but inside
* the display panel.
*
* @return The current outside-the-graph tool-tip text.
*/
public static String getToolTipText() {
return(toolTipText);
}
/*
* global options
*/
/**
* Boolean to indicate if all element attributes should be printed.
* By default, only the element specific attributes are printed and
* attributes inherited from a parent element (subgraph) are skipped.
*
* @see Subgraph#printSubgraph
* @see Element#printAllAttributes
*/
public static boolean elementPrintAllAttributes = false;
/**
* Boolean to indicate if the default attributes associated with
* a subgraph should be printed.
* By default, only those differing from the pre-defined defaults are
* printed.
*
* @see Subgraph#printSubgraph
* @see Element#printDefaultAttributes
*/
public static boolean elementPrintDefaultAttributes = false;
/**
* Indicates if element text should be included in the element
* bounding box. By default, it is.
*
* @see GrappaNexus#boundText
*/
public static boolean shapeBoundText = true;
/**
* Indicates if the area bounding the element text should be
* filled/outlined along with the element when being drawn.
* By default, it is not.
*
* @see GrappaNexus#clearText
*/
public static boolean shapeClearText = false;
/**
* Indicates if element text should be drawn when drawing the
* element. By default, it is.
*
* @see GrappaNexus#drawText
*/
public static boolean shapeDrawText = true;
/**
* Indicates if element node position indicates the node center
* point. Otherwise, the position is assumed to indicate the
* upper-left corner of the nodes bounding box.
* By default, the position indicates the node’s center point.
*/
public static boolean centerPointNodes = true;
/**
* Indicates if the label position for node labels should automatically
* be set to the center point of the node. When true, positioning
* information provided by the lp attribute is completely
* ignored. By default, auto-positioning is used.
*/
public static boolean autoPositionNodeLabel = true;
// not used
//public static boolean graphAutoUpdate = false;
/**
* Indicates if the bb attribute of a subgraph should
* automatically be set whenever the bounding box is calculated.
* By default, the attribute is not set automatically.
*/
public static boolean provideBBoxAttribute = false;
/**
* Indicates what winding rule to use whenever a winding rule is
* required. The default is the java.awt.geom.PathIterator
* WIND_NON_ZERO rule.
*/
public static int windingRule = java.awt.geom.PathIterator.WIND_NON_ZERO;
/**
* Indicates whether the orientation attribute is specifed
* in degrees rather than radians. Degrees is the default.
*/
public static boolean orientationInDegrees = true;
/**
* Indicates whether the rotation attribute is specifed
* in degrees rather than radians. Degrees is the default.
*/
public static boolean rotationInDegrees = true;
/**
* Indicates whether only the list of attributes found in the
* PRINTLIST_ATTR should be printed. See also printVisibleOnly.
* The default is false.
*/
public static boolean usePrintList = false;
/**
* Indicates whether only visible elements should be included
* when printing a graph.
* The default is false.
*/
public static boolean printVisibleOnly = false;
/**
* Indicates whether anti-aliasing should be used when drawing.
* The default is true.
*/
public static boolean useAntiAliasing = true;
/**
* Indicates whether anti-aliasing should be used when drawing text.
* The default is false.
*/
public static boolean antiAliasText = false;
/**
* Indicates whether fractional metrics should be used when drawing text.
* The default is false.
*/
public static boolean useFractionalMetrics = false;
/**
* Indicates whether the value of y-coordinates should be negated
* when reading or writing y-coord information as string attributes.
* Note: this indicator should be set to true when working
* with string attributes generated by or to be read by the dot
* graph layout program or to be compatible to earlier versions of Grappa.
* The default is true.
*/
public static boolean negateStringYCoord = true;
/**
* Indicates that graph labels, when not explicitly positioned via
* the lp attribute, should be placed at the bottom of the
* graph instead of the top. The default is true, meaning the label
* will be placed at the bottom of the graph.
*/
public static boolean labelGraphBottom = true;
/**
* Indicates that graph labels, when not explicitly positioned via
* the lp attribute, should be placed just outside the
* graph bounding box instead of just inside. The default is true,
* meaning the label will be placed outside the bounding box.
*/
public static boolean labelGraphOutside = true;
/**
* Indicates that background drawing, if any is provided via
* a GrappaBacker implementation, should be displayed
* or not. The default of true means the background drawing should
* be displayed, if provided.
*/
public static boolean backgroundDrawing = true;
/**
* When the transform scale applied when drawing in a GrappaPanel is
* less than this value, then node labels are suppressed.
*
*/
public static double nodeLabelsScaleCutoff = 0.5;
/**
* Cluster subgraphs will have their bounding box outlined. To
* similarly outline all types of subgraphs (except the root subgraph),
* set this value to true.
*
*/
public static boolean outlineSubgraphs = false;
/**
* When the transform scale applied when drawing in a GrappaPanel is
* less than this value, then edge labels are suppressed.
*
*/
public static double edgeLabelsScaleCutoff = 0.5;
/**
* When the transform scale applied when drawing in a GrappaPanel is
* less than this value, then subgraph labels are suppressed.
*
*/
public static double subgLabelsScaleCutoff = 0.3;
/**
* Indicates whether paints should be done within a synchronized
* wrapper. When enable the Graph dropcloth method can be used to
* prevent paints during certain critical operations.
*
* @see Graph#dropcloth(boolan, boolean)
*/
public static boolean synchronizePaint = false;
/**
* Indicates that an image requested via the IMAGE_ATTR of
* an element should be loaded before the element is drawn.
* By default, Grappa will wait.
*
* @see GrappaNexus#drawImage
*/
public static boolean waitForImages = true;
/**
* Indicates which classes of elements are suitable for selection
* based on cursor position. Value is the logical OR of NODE,
* EDGE and SUBGRAPH. The default is SUBGRAPH|NODE|EDGE.
*
*/
public static int elementSelection = SUBGRAPH|NODE|EDGE;
}
att/grappa/GrappaAdapter.java
att/grappa/GrappaAdapter.java/*
* This software may only be used by you under license from AT&T Corp.
* (“AT&T”). A copy of AT&T’s Source Code Agreement is available at
* AT&T’s Internet website having the URL:
*
* If you received this software without first entering into a license
* with AT&T, you have an infringing copy of this software and cannot use
* it without violating AT&T’s intellectual property rights.
*/
package att.grappa;
import java.awt.*;
import java.awt.print.*;
import java.awt.geom.AffineTransform;
import java.awt.geom.Dimension2D;
import java.awt.geom.Rectangle2D;
import java.awt.event.InputEvent;
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;
import java.util.*;
/**
* A convenience class that implements the GrappaListener interface
* for handling mouse-related activity that occurs on a graph.
*
* This particular GrappaListener implementation allows the following
* interactions with a displayed graph:
*
*
* display tooltips for each graph element;
*
* button-1 click will select an element;
*
* button-1 sweep will select several elements;
*
* shift-button 1 click will create a node;
*
* shift-button 1 drag, when starting in one node and ending in another, will create an edge;
*
* button-2 or button-3 click will raise a pop-up option menu with:
*
* zoom in, zoom out and reset zoom options;
*
* a zoom-to-sweep option, if applicable;
*
* clear selection, enclose the selected items in a new subgraph,
* preview deletion, cancel preview and perform deletion, if at least
* one item is selected;
*
* a tooltip on/off toggle option.
*
*
*
*
*
* @version 1.2, 26 May 2005; Copyright 1996 – 2005 by AT&T Corp.
* @author John Mocenigo, Research @ AT&T Labs
*/
public class GrappaAdapter
implements GrappaConstants, GrappaListener, ActionListener
{
/**
* The method called when a mouse click occurs on a displayed subgraph.
*
* @param subg displayed subgraph where action occurred
* @param elem subgraph element in which action occurred
* @param pt the point where the action occurred (graph coordinates)
* @param modifiers mouse modifiers in effect
* @param clickCount count of mouse clicks that triggered this action
* @param panel specific panel where the action occurred
*/
public void grappaClicked(Subgraph subg, Element elem, GrappaPoint pt, int modifiers, int clickCount, GrappaPanel panel) {
if((modifiers&InputEvent.BUTTON1_MASK) == InputEvent.BUTTON1_MASK) {
if(clickCount == 1) {
// looks like Java has a single click occur on the way to a
// multiple click, so this code always executes (which is
// not necessarily a bad thing)
if(subg.getGraph().isSelectable()) {
if(modifiers == InputEvent.BUTTON1_MASK) {
// select element
if(elem == null) {
if(subg.currentSelection != null) {
if(subg.currentSelection instanceof Element) {
((Element)(subg.currentSelection)).highlight &= ~HIGHLIGHT_MASK;
} else {
Vector vec = ((Vector)(subg.currentSelection));
for(int i = 0; i < vec.size(); i++) { ((Element)(vec.elementAt(i))).highlight &= ~HIGHLIGHT_MASK; } } subg.currentSelection = null; subg.getGraph().repaint(); } } else { if(subg.currentSelection != null) { if(subg.currentSelection == elem) return; if(subg.currentSelection instanceof Element) { ((Element)(subg.currentSelection)).highlight &= ~HIGHLIGHT_MASK; } else { Vector vec = ((Vector)(subg.currentSelection)); for(int i = 0; i < vec.size(); i++) { ((Element)(vec.elementAt(i))).highlight &= ~HIGHLIGHT_MASK; } } subg.currentSelection = null; } elem.highlight |= SELECTION_MASK; subg.currentSelection = elem; subg.getGraph().repaint(); } } else if(modifiers == (InputEvent.BUTTON1_MASK|InputEvent.CTRL_MASK)) { // adjust selection if(elem != null) { if((elem.highlight&SELECTION_MASK) == SELECTION_MASK) { // unselect element elem.highlight &= ~SELECTION_MASK; if(subg.currentSelection == null) { // something got messed up somewhere throw new InternalError("currentSelection improperly maintained"); } else if(subg.currentSelection instanceof Element) { if(((Element)(subg.currentSelection)) != elem) { // something got messed up somewhere throw new InternalError("currentSelection improperly maintained"); } subg.currentSelection = null; } else { Vector vec = ((Vector)(subg.currentSelection)); boolean problem = true; for(int i = 0; i < vec.size(); i++) { if(((Element)(vec.elementAt(i))) == elem) { vec.removeElementAt(i); problem = false; break; } } if(problem) { // something got messed up somewhere throw new InternalError("currentSelection improperly maintained"); } } } else { // select element elem.highlight |= SELECTION_MASK; if(subg.currentSelection == null) { subg.currentSelection = elem; } else if(subg.currentSelection instanceof Element) { Object obj = subg.currentSelection; subg.currentSelection = new Vector(); ((Vector)(subg.currentSelection)).add(obj); ((Vector)(subg.currentSelection)).add(elem); } else { ((Vector)(subg.currentSelection)).add(elem); } } subg.getGraph().repaint(); } } } } else { // multiple clicks // this code executes for each click beyond the first //System.err.println("clickCount="+clickCount); } } } /** * The method called when a mouse press occurs on a displayed subgraph. * * @param subg displayed subgraph where action occurred * @param elem subgraph element in which action occurred * @param pt the point where the action occurred (graph coordinates) * @param modifiers mouse modifiers in effect * @param panel specific panel where the action occurred */ public void grappaPressed(Subgraph subg, Element elem, GrappaPoint pt, int modifiers, GrappaPanel panel) { if((modifiers&(InputEvent.BUTTON2_MASK|InputEvent.BUTTON3_MASK)) != 0 && (modifiers&(InputEvent.BUTTON2_MASK|InputEvent.BUTTON3_MASK)) == modifiers) { // pop-up menu if button2 or button3 javax.swing.JPopupMenu popup = new javax.swing.JPopupMenu(); javax.swing.JMenuItem item = null; if(panel.getToolTipText() == null) { popup.add(item = new javax.swing.JMenuItem("ToolTips On")); } else { popup.add(item = new javax.swing.JMenuItem("ToolTips Off")); } item.addActionListener(this); popup.addSeparator(); popup.add(item = new javax.swing.JMenuItem("Print")); item.addActionListener(this); popup.addSeparator(); if(subg.currentSelection != null) { popup.add(item = new javax.swing.JMenuItem("Clear Selection")); item.addActionListener(this); popup.addSeparator(); if(subg.currentSelection instanceof Element) { popup.add(item = new javax.swing.JMenuItem("Select Siblings in Subgraph")); item.addActionListener(this); popup.addSeparator(); } popup.add(item = new javax.swing.JMenuItem("Enclose Selected Items in a new Subgraph")); item.addActionListener(this); popup.addSeparator(); popup.add(item = new javax.swing.JMenuItem("Preview Deletion")); item.addActionListener(this); popup.add(item = new javax.swing.JMenuItem("Cancel Preview")); item.addActionListener(this); popup.add(item = new javax.swing.JMenuItem("Perform Deletion")); item.addActionListener(this); popup.addSeparator(); } if(panel.hasOutline()) { popup.add(item = new javax.swing.JMenuItem("Zoom to Sweep")); item.addActionListener(this); } popup.add(item = new javax.swing.JMenuItem("Zoom In")); item.addActionListener(this); popup.add(item = new javax.swing.JMenuItem("Zoom Out")); item.addActionListener(this); popup.add(item = new javax.swing.JMenuItem("Reset Zoom")); item.addActionListener(this); popup.add(item = new javax.swing.JMenuItem("Scale to Fit")); item.addActionListener(this); if(subg.hasEmptySubgraphs()) { popup.addSeparator(); popup.add(item = new javax.swing.JMenuItem("Remove Empty Subgraphs")); item.addActionListener(this); } java.awt.geom.Point2D mpt = panel.getTransform().transform(pt,null); popup.show(panel,(int)mpt.getX(),(int)mpt.getY()); } } /** * The method called when a mouse release occurs on a displayed subgraph. * * @param subg displayed subgraph where action occurred * @param elem subgraph element in which action occurred * @param pt the point where the action occurred (graph coordinates) * @param modifiers mouse modifiers in effect * @param pressedElem subgraph element in which the most recent mouse press occurred * @param pressedPt the point where the most recent mouse press occurred (graph coordinates) * @param pressedModifiers mouse modifiers in effect when the most recent mouse press occurred * @param outline enclosing box specification from the previous drag position (for XOR reset purposes) * @param panel specific panel where the action occurred */ public void grappaReleased(Subgraph subg, Element elem, GrappaPoint pt, int modifiers, Element pressedElem, GrappaPoint pressedPt, int pressedModifiers, GrappaBox outline, GrappaPanel panel) { if(modifiers == InputEvent.BUTTON1_MASK && subg.getGraph().isSelectable()) { if(outline != null) { boolean xorOutline = false; if(subg.currentSelection != null) { if(subg.currentSelection instanceof Element) { ((Element)(subg.currentSelection)).highlight = 0; } else { Vector vec = ((Vector)(subg.currentSelection)); for(int i = 0; i < vec.size(); i++) { ((Element)(vec.elementAt(i))).highlight = 0; } } subg.currentSelection = null; } Vector elems = GrappaSupport.findContainedElements(subg, outline); if(elems != null) { drillDown(subg, elems, SELECTION_MASK, HIGHLIGHT_ON); xorOutline = false; } if(!xorOutline) { subg.getGraph().paintImmediately(); } if(xorOutline) { Graphics2D g2d = (Graphics2D)(panel.getGraphics()); AffineTransform orig = g2d.getTransform(); g2d.setTransform(panel.getTransform()); g2d.setXORMode(Color.darkGray); g2d.draw(outline); g2d.setPaintMode(); g2d.setTransform(orig); } } } else if(modifiers == (InputEvent.BUTTON1_MASK|InputEvent.CTRL_MASK) && subg.getGraph().isSelectable()) { if(outline != null) { Vector elems = GrappaSupport.findContainedElements(subg, outline); if(elems != null) { drillDown(subg, elems, SELECTION_MASK, HIGHLIGHT_TOGGLE); subg.getGraph().repaint(); } else { Graphics2D g2d = (Graphics2D)(panel.getGraphics()); AffineTransform orig = g2d.getTransform(); g2d.setTransform(panel.getTransform()); g2d.setXORMode(Color.darkGray); g2d.draw(outline); g2d.setPaintMode(); g2d.setTransform(orig); } } } else if(modifiers == (InputEvent.BUTTON1_MASK|InputEvent.SHIFT_MASK) && subg.getGraph().isEditable()) { if(elem != null && pressedElem != null) { if(pressedModifiers == modifiers) { if(outline == null) { if(pressedElem == elem && pt.distance(pressedPt) < 5) { // [should we only allow elem.isSubgraph()?] // create node Attribute[] attrs = null; Attribute attr = subg.getNodeAttribute(LABEL_ATTR); if(attr == null || attr.getValue().equals("\\N")) { attrs = new Attribute[] { new Attribute(Grappa.NODE, POS_ATTR, pt), new Attribute(Grappa.NODE, LABEL_ATTR, "Node" + subg.getGraph().getId(Grappa.NODE)) }; } else { attrs = new Attribute[] { new Attribute(Grappa.NODE, POS_ATTR, pt) }; } Element el = subg.createElement(Grappa.NODE,null,attrs); if(el != null) { el.buildShape(); subg.getGraph().repaint(); } subg.getGraph().repaint(); } else if(pressedElem != elem && pressedElem.isNode() && elem.isNode()) { // create edge Object[] info = new Object[] { elem, null, pressedElem }; Attribute[] attrs = new Attribute[] { new Attribute(Grappa.EDGE, POS_ATTR, new GrappaLine(new GrappaPoint[] { ((Node)pressedElem).getCenterPoint(), ((Node)elem).getCenterPoint() }, subg.getGraph().isDirected()?GrappaLine.TAIL_ARROW_EDGE:GrappaLine.NONE_ARROW_EDGE) ) }; Element el = subg.createElement(Grappa.EDGE,info,attrs); if(el != null) { el.buildShape(); subg.getGraph().repaint(); } } } } } } } /** * The method called when a mouse drag occurs on a displayed subgraph. * * @param subg displayed subgraph where action occurred * @param currentPt the current drag point * @param currentModifiers the current drag mouse modifiers * @param pressedElem subgraph element in which the most recent mouse press occurred * @param pressedPt the point where the most recent mouse press occurred (graph coordinates) * @param pressedModifiers mouse modifiers in effect when the most recent mouse press occurred * @param outline enclosing box specification from the previous drag position (for XOR reset purposes) * @param panel specific panel where the action occurred */ public void grappaDragged(Subgraph subg, GrappaPoint currentPt, int currentModifiers, Element pressedElem, GrappaPoint pressedPt, int pressedModifiers, GrappaBox outline, GrappaPanel panel) { if((currentModifiers&InputEvent.BUTTON1_MASK) == InputEvent.BUTTON1_MASK) { if(currentModifiers == InputEvent.BUTTON1_MASK || currentModifiers == (InputEvent.BUTTON1_MASK|InputEvent.CTRL_MASK)) { Graphics2D g2d = (Graphics2D)(panel.getGraphics()); AffineTransform orig = g2d.getTransform(); g2d.setTransform(panel.getTransform()); g2d.setXORMode(Color.darkGray); if(outline != null) { g2d.draw(outline); } GrappaBox box = GrappaSupport.boxFromCorners(pressedPt.x, pressedPt.y, currentPt.x, currentPt.y); g2d.draw(box); g2d.setPaintMode(); g2d.setTransform(orig); } } } /** * The method called when a element tooltip is needed. * * @param subg displayed subgraph where action occurred * @param elem subgraph element in which action occurred * @param pt the point where the action occurred (graph coordinates) * @param modifiers mouse modifiers in effect * @param panel specific panel where the action occurred * * @return the tip to be displayed or null; in this implementation, * if the mouse is in a graph element that * has its tip attribute defined, then that text is returned.
* If that attribute is not set, the element name is returned.
* If the mouse is outside the graph bounds, then the text supplied
* to the graph setToolTipText method is supplied.
*/
public String grappaTip(Subgraph subg, Element elem, GrappaPoint pt, int modifiers, GrappaPanel panel) {
String tip = null;
if(elem == null) {
if((tip = panel.getToolTipText()) == null) {
if((tip = subg.getGraph().getToolTipText()) == null) {
tip = Grappa.getToolTipText();
}
}
} else {
switch(elem.getType()) {
case SUBGRAPH:
Subgraph sg = (Subgraph)elem;
if((tip = (String)sg.getAttributeValue(TIP_ATTR)) == null) {
if(subg.getShowSubgraphLabels()) {
tip = sg.getName();
} else {
if((tip = (String)sg.getAttributeValue(LABEL_ATTR)) == null) {
tip = sg.getName();
}
}
tip = “Subgraph: ” + tip;
}
break;
case EDGE:
Edge edge = (Edge)elem;
if((tip = (String)edge.getAttributeValue(TIP_ATTR)) == null) {
if(subg.getShowEdgeLabels()) {
tip = edge.toString();
} else {
if((tip = (String)edge.getAttributeValue(LABEL_ATTR)) == null) {
tip = edge.toString();
}
}
tip = “Edge: ” + tip;
}
break;
case NODE:
Node node = (Node)elem;
if((tip = (String)node.getAttributeValue(TIP_ATTR)) == null) {
if(subg.getShowNodeLabels()) {
tip = node.getName();
} else {
if((tip = (String)node.getAttributeValue(LABEL_ATTR)) == null || tip.equals(“\\N”)) {
tip = node.getName();
}
}
tip = “Node: ” + tip;
}
break;
default:
throw new RuntimeException(“unexpected type (” + elem.getType() + “)”);
}
}
return(tip);
}
///////////////////////////////////////////////////////////////////////////
//
// ActionListener
//
///////////////////////////////////////////////////////////////////////////
/**
* Invoked when an action occurs.
*
* @param aev the action event trigger.
*/
public void actionPerformed(ActionEvent aev) {
Object src = aev.getSource();
if(src instanceof javax.swing.JMenuItem) {
Object parent = ((javax.swing.JMenuItem)src).getParent();
if(parent instanceof javax.swing.JPopupMenu) {
Object invoker = ((javax.swing.JPopupMenu)(((javax.swing.JMenuItem)src).getParent())).getInvoker();
if(invoker instanceof GrappaPanel) {
GrappaPanel gp = (GrappaPanel)invoker;
Subgraph subg = gp.getSubgraph();
String text = ((javax.swing.JMenuItem)src).getText();
if(text.startsWith(“Cancel”)) {
if(subg.currentSelection == null) return;
if(subg.currentSelection instanceof Element) {
GrappaSupport.setHighlight((Element)(subg.currentSelection), DELETION_MASK, HIGHLIGHT_OFF);
} else {
Vector vec = (Vector)(subg.currentSelection);
for(int i = 0; i < vec.size(); i++) {
GrappaSupport.setHighlight((Element)(vec.elementAt(i)), DELETION_MASK, HIGHLIGHT_OFF);
}
}
subg.getGraph().repaint();
} else if(text.startsWith("Clear")) {
if(subg.currentSelection == null) return;
if(subg.currentSelection instanceof Element) {
GrappaSupport.setHighlight((Element)(subg.currentSelection), 0, HIGHLIGHT_OFF);
} else {
Vector vec = (Vector)(subg.currentSelection);
for(int i = 0; i < vec.size(); i++) {
GrappaSupport.setHighlight((Element)(vec.elementAt(i)), 0, HIGHLIGHT_OFF);
}
}
subg.currentSelection = null;
subg.getGraph().repaint();
} else if(text.startsWith("Select")) {
if(subg.currentSelection == null) return;
if(!(subg.currentSelection instanceof Element)) return;
Element elem = ((Element)subg.currentSelection).getSubgraph();
if(elem == null || subg.currentSelection == elem || !(elem instanceof Subgraph)) return;
((Element)(subg.currentSelection)).highlight &= ~HIGHLIGHT_MASK;
Vector elems = new Vector();
Enumeration enm = ((Subgraph)elem).nodeElements();
while(enm.hasMoreElements())
elems.add(enm.nextElement());
enm = ((Subgraph)elem).edgeElements();
while(enm.hasMoreElements())
elems.add(enm.nextElement());
subg.currentSelection = null;
if(elems != null && elems.size() > 0)
drillDown(subg, elems, SELECTION_MASK, HIGHLIGHT_ON);
subg.getGraph().repaint();
} else if(text.startsWith(“Enclose”)) {
if(subg.currentSelection == null || subg.currentSelection == subg) return;
Subgraph newsubg = new Subgraph(subg);
if(subg.currentSelection instanceof Element) {
GrappaSupport.setHighlight((Element)(subg.currentSelection), 0, HIGHLIGHT_OFF);
((Element)(subg.currentSelection)).setSubgraph(newsubg);
} else {
Vector vec = (Vector)(subg.currentSelection);
for(int i = 0; i < vec.size(); i++) {
GrappaSupport.setHighlight((Element)(vec.elementAt(i)), 0, HIGHLIGHT_OFF);
if(((Element)(vec.elementAt(i))) == subg) continue;
((Element)(vec.elementAt(i))).setSubgraph(newsubg);
}
}
subg.currentSelection = null;
subg.getGraph().repaint();
} else if(text.startsWith("Preview")) {
if(subg.currentSelection == null) return;
if(subg.currentSelection instanceof Element) {
GrappaSupport.setHighlight((Element)(subg.currentSelection), DELETION_MASK, HIGHLIGHT_ON);
} else {
Vector vec = (Vector)(subg.currentSelection);
for(int i = 0; i < vec.size(); i++) {
GrappaSupport.setHighlight((Element)(vec.elementAt(i)), DELETION_MASK, HIGHLIGHT_ON);
}
}
subg.getGraph().repaint();
} else if(text.startsWith("Perform")) {
if(subg.currentSelection == null) return;
if(subg.currentSelection instanceof Element) {
((Element)(subg.currentSelection)).delete();
} else {
Vector vec = (Vector)(subg.currentSelection);
for(int i = 0; i < vec.size(); i++) {
((Element)(vec.elementAt(i))).delete();
}
}
subg.currentSelection = null;
subg.getGraph().repaint();
} else if(text.startsWith("Remove")) {
subg.removeEmptySubgraphs();
} else if(text.startsWith("Reset")) {
gp.setScaleToFit(false);
gp.setScaleToSize(null);
gp.resetZoom();
gp.clearOutline();
} else if(text.startsWith("Scale")) {
gp.setScaleToFit(true);
} else if(text.startsWith("Print")) {
PageFormat pf = new PageFormat();
Rectangle2D bb = subg.getBoundingBox();
if(bb.getWidth() > bb.getHeight())
pf.setOrientation(PageFormat.LANDSCAPE);
try {
PrinterJob printJob = PrinterJob.getPrinterJob();
printJob.setPrintable(gp, pf);
if (printJob.printDialog()) {
printJob.print();
}
} catch (Exception ex) {
Grappa.displayException(ex, “Problem with print request”);
}
} else if(text.startsWith(“ToolTips”)) {
if(text.indexOf(“Off”) > 0) {
gp.setToolTipText(null);
} else {
String tip = subg.getGraph().getToolTipText();
if(tip == null) {
tip = Grappa.getToolTipText();
}
gp.setToolTipText(tip);
}
} else if(text.startsWith(“Zoom In”)) {
gp.setScaleToFit(false);
gp.setScaleToSize(null);
gp.multiplyScaleFactor(1.25);
gp.clearOutline();
} else if(text.startsWith(“Zoom Out”)) {
gp.setScaleToFit(false);
gp.setScaleToSize(null);
gp.multiplyScaleFactor(0.8);
gp.clearOutline();
} else if(text.startsWith(“Zoom to”)) {
//if(subg.currentSelection == null) return;
gp.setScaleToFit(false);
gp.setScaleToSize(null);
gp.zoomToOutline();
gp.clearOutline();
}
}
}
}
}
///////////////////////////////////////////////////////////////////////////
protected void drillDown(Subgraph subg, Vector elems, int mode, int setting) {
Object obj = null;
for(int i = 0; i < elems.size(); i++) {
obj = elems.elementAt(i);
if(obj instanceof Vector) {
drillDown(subg, (Vector)obj, mode, setting);
} else {
GrappaSupport.setHighlight(((Element)obj), mode, setting);
switch(setting) {
case HIGHLIGHT_TOGGLE:
if((((Element)obj).highlight&mode) == mode) {
if(subg.currentSelection == null) {
subg.currentSelection = obj;
} else if(subg.currentSelection instanceof Element) {
Object crnt = subg.currentSelection;
subg.currentSelection = new Vector();
((Vector)(subg.currentSelection)).add(crnt);
((Vector)(subg.currentSelection)).add(obj);
} else {
((Vector)(subg.currentSelection)).add(obj);
}
} else {
if(subg.currentSelection == obj) {
subg.currentSelection = null;
} else if(subg.currentSelection instanceof Vector) {
((Vector)(subg.currentSelection)).remove(obj);
}
}
break;
case HIGHLIGHT_ON:
if(subg.currentSelection == null) {
subg.currentSelection = obj;
} else if(subg.currentSelection instanceof Element) {
Object crnt = subg.currentSelection;
subg.currentSelection = new Vector();
((Vector)(subg.currentSelection)).add(crnt);
((Vector)(subg.currentSelection)).add(obj);
} else {
((Vector)(subg.currentSelection)).add(obj);
}
break;
case HIGHLIGHT_OFF:
if(subg.currentSelection != null) {
if(subg.currentSelection == obj) {
subg.currentSelection = null;
} else if(subg.currentSelection instanceof Vector) {
((Vector)(subg.currentSelection)).remove(obj);
}
}
break;
}
}
}
}
}
att/grappa/GrappaBacker.java
att/grappa/GrappaBacker.java/*
* This software may only be used by you under license from AT&T Corp.
* ("AT&T"). A copy of AT&T's Source Code Agreement is available at
* AT&T's Internet website having the URL:
*
* If you received this software without first entering into a license
* with AT&T, you have an infringing copy of this software and cannot use
* it without violating AT&T’s intellectual property rights.
*/
package att.grappa;
/**
* An interface for defining an image drawing method to be used for
* painting the background of the graph.
*
* @version 1.2, 26 May 2005; Copyright 1996 – 2005 by AT&T Corp.
* @author John Mocenigo, Research @ AT&T Labs
*/
public interface GrappaBacker
{
/**
* The method for drawing the background image.
*
* @param g2d the graphics context.
* @param graph the graph being drawn in the foreground.
* @param bbox the bounding box of the graph.
* @param clip the clipping shape defining the limits of the area to be drawn.
*/
public void drawBackground(java.awt.Graphics2D g2d, Graph graph, java.awt.geom.Rectangle2D bbox, java.awt.Shape clip);
}
att/grappa/GrappaBox.java
att/grappa/GrappaBox.java/*
* This software may only be used by you under license from AT&T Corp.
* (“AT&T”). A copy of AT&T’s Source Code Agreement is available at
* AT&T’s Internet website having the URL:
*
* If you received this software without first entering into a license
* with AT&T, you have an infringing copy of this software and cannot use
* it without violating AT&T’s intellectual property rights.
*/
package att.grappa;
/**
* This class extends java.awt.geom.Rectangle2D.Double and provides built-in
* string-to-Rectangle2D and Rectangle2D-to-string conversions suitable for Grappa.
*
* @version 1.2, 26 May 2005; Copyright 1996 – 2005 by AT&T Corp.
* @author John Mocenigo, Research @ AT&T Labs
*/
public class GrappaBox extends java.awt.geom.Rectangle2D.Double
{
private boolean dimensioned = true;
/**
* Constructs and initializes a GrappaBox
with
* upper-left coordinates (0, 0) and zero width and height.
*/
public GrappaBox() {
}
/**
* Constructs and initializes a GrappaBox
from a
* Rectangle2D
* @param r the rectangle defining the box (1-to-1 correspondence)
*/
public GrappaBox(java.awt.geom.Rectangle2D r) {
this(r.getX(),r.getY(),r.getWidth(),r.getHeight());
}
/**
* Constructs and initializes a GrappaBox
with the
* specified coordinates.
* @param x, y the upper-left position coordinates of the box
* @param width, height the size of the box
*/
public GrappaBox(double x, double y, double width, double height) {
this.x = x;
this.y = y;
this.width = width;
this.height = height;
}
/**
* Constructs and initializes a GrappaBox
with the
* coordinates derived from the specified String representation.
* When the dimensioned parameter is true, then the String
* format should be:
* “x-coord,y-coord,width,height”
* otherwise it should be:
* “x1-coord,y1-coord,x2-coord,y2-coord”
* @param coordString String representing the coordinates to which to
* set the newly constructed GrappaBox
* @param dimensioned a boolean indicating the format of the string
*/
public GrappaBox(String coordString, boolean dimensioned) {
this.dimensioned = dimensioned;
double[] coords = null;
try {
coords = GrappaSupport.arrayForTuple(coordString);
}
catch(NumberFormatException nfe) {
throw new IllegalArgumentException(“coordinate string (” + coordString + “) has a bad number format (” + nfe.getMessage() + “)”);
}
if(coords == null || coords.length != 4) {
throw new IllegalArgumentException(“coordinate string (” + coordString + “) does not contain 4 valid coordinates”);
}
if(dimensioned) { // x1, y2, width, height
this.x = coords[0];
this.y = (Grappa.negateStringYCoord?-coords[1]:coords[1]);
this.width = coords[2];
this.height = coords[3];
} else { // x1, y1, x2, y2
double tmp;
if(Grappa.negateStringYCoord) {
coords[1] = -coords[1];
coords[3] = -coords[3];
}
if(coords[0] > coords[2]) {
tmp = coords[0];
coords[0] = coords[2];
coords[2] = tmp;
}
if(coords[1] > coords[3]) {
tmp = coords[1];
coords[1] = coords[3];
coords[3] = tmp;
}
this.x = coords[0];
this.y = coords[1];
this.width = coords[2] – coords[0];
this.height = coords[3] – coords[1];
}
}
/**
* Constructs and initializes a GrappaBox
with the
* coordinates derived from the specified String representation.
* The String format should be: “x-coord,y-coord,width,height“”
* @param coordString String representing the coordinates to which to
* set the newly constructed GrappaBox
*/
public GrappaBox(String coordString) {
this(coordString, true);
}
/**
* Provides a string representation of this object consistent
* with Grappa attributes.
*
* @return attribute-suitable string representation of this GrappaBox.
*/
public String toAttributeString() {
return(toFormattedString(“%b”));
}
/**
* Provides a formatted string representation of this object.
*
* @param format the format used to build the string (%b is the base directive for a GrappaBox).
* @return a string representation of this GrappaBox.
*/
public String toFormattedString(String format) {
return(GrappaSupportPrintf.sprintf(new Object[] { format, this }));
}
/**
* Provides a generic string representation of this object.
*
* @return a generic string representation of this GrappaBox.
*/
public String toString() {
return(x+”,”+y+”,”+width+”,”+height);
}
/**
* Returns true if the String format will be “x1,x2,width,height”
* or false if the format will be “x1,y1,x2,y2”. The value is
* determined at creation time.
*
* @return a boolean indicating the format of this Object’s string representation
*/
public boolean isDimensioned() {
return(dimensioned);
}
}
att/grappa/GrappaColor.java
att/grappa/GrappaColor.java/*
* This software may only be used by you under license from AT&T Corp.
* (“AT&T”). A copy of AT&T’s Source Code Agreement is available at
* AT&T’s Internet website having the URL:
*
* If you received this software without first entering into a license
* with AT&T, you have an infringing copy of this software and cannot use
* it without violating AT&T’s intellectual property rights.
*/
package att.grappa;
import java.awt.*;
import java.util.*;
/**
* This abstract class sets up and provides name-to-color and color-to-name
* mappings and some associated class methods.
*
* @version 1.2, 26 May 2005; Copyright 1996 – 2005 by AT&T Corp.
* @author John Mocenigo, Research @ AT&T Labs
*/
public abstract class GrappaColor
{
// given name, get color
private static Hashtable colorTable = new Hashtable(660,10);
// given color, get name
private static Hashtable colorLookUp = new Hashtable(660,10);
// initialize colorTable
static {
doAddColor(“aliceblue”,new Color(240,248,255));
doAddColor(“antiquewhite”,new Color(250,235,215));
doAddColor(“antiquewhite1”,new Color(255,239,219),false);
doAddColor(“antiquewhite2”,new Color(238,223,204),false);
doAddColor(“antiquewhite3”,new Color(205,192,176),false);
doAddColor(“antiquewhite4”,new Color(139,131,120),false);
doAddColor(“aquamarine”,new Color(127,255,212));
doAddColor(“aquamarine1”,new Color(127,255,212),false);
doAddColor(“aquamarine2”,new Color(118,238,198),false);
doAddColor(“aquamarine3”,new Color(102,205,170),false);
doAddColor(“aquamarine4”,new Color(69,139,116),false);
doAddColor(“azure”,new Color(240,255,255));
doAddColor(“azure1”,new Color(240,255,255),false);
doAddColor(“azure2”,new Color(224,238,238),false);
doAddColor(“azure3”,new Color(193,205,205),false);
doAddColor(“azure4”,new Color(131,139,139),false);
doAddColor(“beige”,new Color(245,245,220));
doAddColor(“bisque”,new Color(255,228,196));
doAddColor(“bisque1”,new Color(255,228,196),false);
doAddColor(“bisque2”,new Color(238,213,183),false);
doAddColor(“bisque3”,new Color(205,183,158),false);
doAddColor(“bisque4”,new Color(139,125,107),false);
doAddColor(“black”,new Color(0,0,0));
doAddColor(“blanchedalmond”,new Color(255,235,205));
doAddColor(“blue”,new Color(0,0,255));
doAddColor(“blue1”,new Color(0,0,255),false);
doAddColor(“blue2”,new Color(0,0,238),false);
doAddColor(“blue3”,new Color(0,0,205),false);
doAddColor(“blue4”,new Color(0,0,139),false);
doAddColor(“blueviolet”,new Color(138,43,226));
doAddColor(“brown”,new Color(165,42,42));
doAddColor(“brown1”,new Color(255,64,64),false);
doAddColor(“brown2”,new Color(238,59,59),false);
doAddColor(“brown3”,new Color(205,51,51),false);
doAddColor(“brown4”,new Color(139,35,35),false);
doAddColor(“burlywood”,new Color(222,184,135));
doAddColor(“burlywood1”,new Color(255,211,155),false);
doAddColor(“burlywood2”,new Color(238,197,145),false);
doAddColor(“burlywood3”,new Color(205,170,125),false);
doAddColor(“burlywood4”,new Color(139,115,85),false);
doAddColor(“cadetblue”,new Color(95,158,160));
doAddColor(“cadetblue1”,new Color(152,245,255),false);
doAddColor(“cadetblue2”,new Color(142,229,238),false);
doAddColor(“cadetblue3”,new Color(122,197,205),false);
doAddColor(“cadetblue4”,new Color(83,134,139),false);
doAddColor(“chartreuse”,new Color(127,255,0));
doAddColor(“chartreuse1”,new Color(127,255,0),false);
doAddColor(“chartreuse2”,new Color(118,238,0),false);
doAddColor(“chartreuse3”,new Color(102,205,0),false);
doAddColor(“chartreuse4”,new Color(69,139,0),false);
doAddColor(“chocolate”,new Color(210,105,30));
doAddColor(“chocolate1”,new Color(255,127,36),false);
doAddColor(“chocolate2”,new Color(238,118,33),false);
doAddColor(“chocolate3”,new Color(205,102,29),false);
doAddColor(“chocolate4”,new Color(139,69,19),false);
doAddColor(“coral”,new Color(255,127,80));
doAddColor(“coral1”,new Color(255,114,86),false);
doAddColor(“coral2”,new Color(238,106,80),false);
doAddColor(“coral3”,new Color(205,91,69),false);
doAddColor(“coral4”,new Color(139,62,47),false);
doAddColor(“cornflowerblue”,new Color(100,149,237));
doAddColor(“cornsilk”,new Color(255,248,220));
doAddColor(“cornsilk1”,new Color(255,248,220),false);
doAddColor(“cornsilk2”,new Color(238,232,205),false);
doAddColor(“cornsilk3”,new Color(205,200,177),false);
doAddColor(“cornsilk4”,new Color(139,136,120),false);
doAddColor(“crimson”,new Color(220,20,60));
doAddColor(“cyan”,new Color(0,255,255));
doAddColor(“cyan1”,new Color(0,255,255),false);
doAddColor(“cyan2”,new Color(0,238,238),false);
doAddColor(“cyan3”,new Color(0,205,205),false);
doAddColor(“cyan4”,new Color(0,139,139),false);
doAddColor(“darkblue”,new Color(0,0,139));
doAddColor(“darkcyan”,new Color(0,139,139));
doAddColor(“darkgoldenrod”,new Color(184,134,11));
doAddColor(“darkgoldenrod1”,new Color(255,185,15),false);
doAddColor(“darkgoldenrod2”,new Color(238,173,14),false);
doAddColor(“darkgoldenrod3”,new Color(205,149,12),false);
doAddColor(“darkgoldenrod4”,new Color(139,101,8),false);
doAddColor(“darkgray”,new Color(169,169,169));
doAddColor(“darkgreen”,new Color(0,100,0));
doAddColor(“darkgrey”,new Color(169,169,169),false);
doAddColor(“darkkhaki”,new Color(189,183,107));
doAddColor(“darkmagenta”,new Color(139,0,139));
doAddColor(“darkolivegreen”,new Color(85,107,47));
doAddColor(“darkolivegreen1”,new Color(202,255,112),false);
doAddColor(“darkolivegreen2”,new Color(188,238,104),false);
doAddColor(“darkolivegreen3”,new Color(162,205,90),false);
doAddColor(“darkolivegreen4”,new Color(110,139,61),false);
doAddColor(“darkorange”,new Color(255,140,0));
doAddColor(“darkorange1”,new Color(255,127,0),false);
doAddColor(“darkorange2”,new Color(238,118,0),false);
doAddColor(“darkorange3”,new Color(205,102,0),false);
doAddColor(“darkorange4”,new Color(139,69,0),false);
doAddColor(“darkorchid”,new Color(153,50,204));
doAddColor(“darkorchid1”,new Color(191,62,255),false);
doAddColor(“darkorchid2”,new Color(178,58,238),false);
doAddColor(“darkorchid3”,new Color(154,50,205),false);
doAddColor(“darkorchid4”,new Color(104,34,139),false);
doAddColor(“darkred”,new Color(139,0,0));
doAddColor(“darksalmon”,new Color(233,150,122));
doAddColor(“darkseagreen”,new Color(143,188,143));
doAddColor(“darkseagreen1”,new Color(193,255,193),false);
doAddColor(“darkseagreen2”,new Color(180,238,180),false);
doAddColor(“darkseagreen3”,new Color(155,205,155),false);
doAddColor(“darkseagreen4”,new Color(105,139,105),false);
doAddColor(“darkslateblue”,new Color(72,61,139));
doAddColor(“darkslategray”,new Color(47,79,79));
doAddColor(“darkslategray1”,new Color(151,255,255),false);
doAddColor(“darkslategray2”,new Color(141,238,238),false);
doAddColor(“darkslategray3”,new Color(121,205,205),false);
doAddColor(“darkslategray4”,new Color(82,139,139),false);
doAddColor(“darkslategrey”,new Color(47,79,79),false);
doAddColor(“darkturquoise”,new Color(0,206,209));
doAddColor(“darkviolet”,new Color(148,0,211));
doAddColor(“deeppink”,new Color(255,20,147));
doAddColor(“deeppink1”,new Color(255,20,147),false);
doAddColor(“deeppink2”,new Color(238,18,137),false);
doAddColor(“deeppink3”,new Color(205,16,118),false);
doAddColor(“deeppink4”,new Color(139,10,80),false);
doAddColor(“deepskyblue”,new Color(0,191,255));
doAddColor(“deepskyblue1”,new Color(0,191,255),false);
doAddColor(“deepskyblue2”,new Color(0,178,238),false);
doAddColor(“deepskyblue3”,new Color(0,154,205),false);
doAddColor(“deepskyblue4”,new Color(0,104,139),false);
doAddColor(“dimgray”,new Color(105,105,105));
doAddColor(“dimgrey”,new Color(105,105,105),false);
doAddColor(“dodgerblue”,new Color(30,144,255));
doAddColor(“dodgerblue1”,new Color(30,144,255),false);
doAddColor(“dodgerblue2”,new Color(28,134,238),false);
doAddColor(“dodgerblue3”,new Color(24,116,205),false);
doAddColor(“dodgerblue4”,new Color(16,78,139),false);
doAddColor(“firebrick”,new Color(178,34,34));
doAddColor(“firebrick1”,new Color(255,48,48),false);
doAddColor(“firebrick2”,new Color(238,44,44),false);
doAddColor(“firebrick3”,new Color(205,38,38),false);
doAddColor(“firebrick4”,new Color(139,26,26),false);
doAddColor(“floralwhite”,new Color(255,250,240));
doAddColor(“forestgreen”,new Color(34,139,34));
doAddColor(“gainsboro”,new Color(220,220,220));
doAddColor(“ghostwhite”,new Color(248,248,255));
doAddColor(“gold”,new Color(255,215,0));
doAddColor(“gold1”,new Color(255,215,0),false);
doAddColor(“gold2”,new Color(238,201,0),false);
doAddColor(“gold3”,new Color(205,173,0),false);
doAddColor(“gold4”,new Color(139,117,0),false);
doAddColor(“goldenrod”,new Color(218,165,32));
doAddColor(“goldenrod1”,new Color(255,193,37),false);
doAddColor(“goldenrod2”,new Color(238,180,34),false);
doAddColor(“goldenrod3”,new Color(205,155,29),false);
doAddColor(“goldenrod4”,new Color(139,105,20),false);
doAddColor(“green”,new Color(0,255,0));
doAddColor(“green1”,new Color(0,255,0),false);
doAddColor(“green2”,new Color(0,238,0),false);
doAddColor(“green3”,new Color(0,205,0),false);
doAddColor(“green4”,new Color(0,139,0),false);
doAddColor(“greenyellow”,new Color(173,255,47));
doAddColor(“gray”,new Color(190,190,190));
doAddColor(“grey”,new Color(190,190,190),false);
doAddColor(“gray0”,new Color(0,0,0),false);
doAddColor(“grey0”,new Color(0,0,0),false);
doAddColor(“gray1”,new Color(3,3,3),false);
doAddColor(“grey1”,new Color(3,3,3),false);
doAddColor(“gray2”,new Color(5,5,5),false);
doAddColor(“grey2”,new Color(5,5,5),false);
doAddColor(“gray3”,new Color(8,8,8),false);
doAddColor(“grey3”,new Color(8,8,8),false);
doAddColor(“gray4”,new Color(10,10,10),false);
doAddColor(“grey4”,new Color(10,10,10),false);
doAddColor(“gray5”,new Color(13,13,13),false);
doAddColor(“grey5”,new Color(13,13,13),false);
doAddColor(“gray6”,new Color(15,15,15),false);
doAddColor(“grey6”,new Color(15,15,15),false);
doAddColor(“gray7”,new Color(18,18,18),false);
doAddColor(“grey7”,new Color(18,18,18),false);
doAddColor(“gray8”,new Color(20,20,20),false);
doAddColor(“grey8”,new Color(20,20,20),false);
doAddColor(“gray9”,new Color(23,23,23),false);
doAddColor(“grey9”,new Color(23,23,23),false);
doAddColor(“gray10”,new Color(26,26,26),false);
doAddColor(“grey10”,new Color(26,26,26),false);
doAddColor(“gray11”,new Color(28,28,28),false);
doAddColor(“grey11”,new Color(28,28,28),false);
doAddColor(“gray12”,new Color(31,31,31),false);
doAddColor(“grey12”,new Color(31,31,31),false);
doAddColor(“gray13”,new Color(33,33,33),false);
doAddColor(“grey13”,new Color(33,33,33),false);
doAddColor(“gray14”,new Color(36,36,36),false);
doAddColor(“grey14”,new Color(36,36,36),false);
doAddColor(“gray15”,new Color(38,38,38),false);
doAddColor(“grey15”,new Color(38,38,38),false);
doAddColor(“gray16”,new Color(41,41,41),false);
doAddColor(“grey16”,new Color(41,41,41),false);
doAddColor(“gray17”,new Color(43,43,43),false);
doAddColor(“grey17”,new Color(43,43,43),false);
doAddColor(“gray18”,new Color(46,46,46),false);
doAddColor(“grey18”,new Color(46,46,46),false);
doAddColor(“gray19”,new Color(48,48,48),false);
doAddColor(“grey19”,new Color(48,48,48),false);
doAddColor(“gray20”,new Color(51,51,51),false);
doAddColor(“grey20”,new Color(51,51,51),false);
doAddColor(“gray21”,new Color(54,54,54),false);
doAddColor(“grey21”,new Color(54,54,54),false);
doAddColor(“gray22”,new Color(56,56,56),false);
doAddColor(“grey22”,new Color(56,56,56),false);
doAddColor(“gray23”,new Color(59,59,59),false);
doAddColor(“grey23”,new Color(59,59,59),false);
doAddColor(“gray24”,new Color(61,61,61),false);
doAddColor(“grey24”,new Color(61,61,61),false);
doAddColor(“gray25”,new Color(64,64,64),false);
doAddColor(“grey25”,new Color(64,64,64),false);
doAddColor(“gray26”,new Color(66,66,66),false);
doAddColor(“grey26”,new Color(66,66,66),false);
doAddColor(“gray27”,new Color(69,69,69),false);
doAddColor(“grey27”,new Color(69,69,69),false);
doAddColor(“gray28”,new Color(71,71,71),false);
doAddColor(“grey28”,new Color(71,71,71),false);
doAddColor(“gray29”,new Color(74,74,74),false);
doAddColor(“grey29”,new Color(74,74,74),false);
doAddColor(“gray30”,new Color(77,77,77),false);
doAddColor(“grey30”,new Color(77,77,77),false);
doAddColor(“gray31”,new Color(79,79,79),false);
doAddColor(“grey31”,new Color(79,79,79),false);
doAddColor(“gray32”,new Color(82,82,82),false);
doAddColor(“grey32”,new Color(82,82,82),false);
doAddColor(“gray33”,new Color(84,84,84),false);
doAddColor(“grey33”,new Color(84,84,84),false);
doAddColor(“gray34”,new Color(87,87,87),false);
doAddColor(“grey34”,new Color(87,87,87),false);
doAddColor(“gray35”,new Color(89,89,89),false);
doAddColor(“grey35”,new Color(89,89,89),false);
doAddColor(“gray36”,new Color(92,92,92),false);
doAddColor(“grey36”,new Color(92,92,92),false);
doAddColor(“gray37”,new Color(94,94,94),false);
doAddColor(“grey37”,new Color(94,94,94),false);
doAddColor(“gray38”,new Color(97,97,97),false);
doAddColor(“grey38”,new Color(97,97,97),false);
doAddColor(“gray39”,new Color(99,99,99),false);
doAddColor(“grey39”,new Color(99,99,99),false);
doAddColor(“gray40”,new Color(102,102,102),false);
doAddColor(“grey40”,new Color(102,102,102),false);
doAddColor(“gray41”,new Color(105,105,105),false);
doAddColor(“grey41”,new Color(105,105,105),false);
doAddColor(“gray42”,new Color(107,107,107),false);
doAddColor(“grey42”,new Color(107,107,107),false);
doAddColor(“gray43”,new Color(110,110,110),false);
doAddColor(“grey43”,new Color(110,110,110),false);
doAddColor(“gray44”,new Color(112,112,112),false);
doAddColor(“grey44”,new Color(112,112,112),false);
doAddColor(“gray45”,new Color(115,115,115),false);
doAddColor(“grey45”,new Color(115,115,115),false);
doAddColor(“gray46”,new Color(117,117,117),false);
doAddColor(“grey46”,new Color(117,117,117),false);
doAddColor(“gray47”,new Color(120,120,120),false);
doAddColor(“grey47”,new Color(120,120,120),false);
doAddColor(“gray48”,new Color(122,122,122),false);
doAddColor(“grey48”,new Color(122,122,122),false);
doAddColor(“gray49”,new Color(125,125,125),false);
doAddColor(“grey49”,new Color(125,125,125),false);
doAddColor(“gray50”,new Color(127,127,127),false);
doAddColor(“grey50”,new Color(127,127,127),false);
doAddColor(“gray51”,new Color(130,130,130),false);
doAddColor(“grey51”,new Color(130,130,130),false);
doAddColor(“gray52”,new Color(133,133,133),false);
doAddColor(“grey52”,new Color(133,133,133),false);
doAddColor(“gray53”,new Color(135,135,135),false);
doAddColor(“grey53”,new Color(135,135,135),false);
doAddColor(“gray54”,new Color(138,138,138),false);
doAddColor(“grey54”,new Color(138,138,138),false);
doAddColor(“gray55”,new Color(140,140,140),false);
doAddColor(“grey55”,new Color(140,140,140),false);
doAddColor(“gray56”,new Color(143,143,143),false);
doAddColor(“grey56”,new Color(143,143,143),false);
doAddColor(“gray57”,new Color(145,145,145),false);
doAddColor(“grey57”,new Color(145,145,145),false);
doAddColor(“gray58”,new Color(148,148,148),false);
doAddColor(“grey58”,new Color(148,148,148),false);
doAddColor(“gray59”,new Color(150,150,150),false);
doAddColor(“grey59”,new Color(150,150,150),false);
doAddColor(“gray60”,new Color(153,153,153),false);
doAddColor(“grey60”,new Color(153,153,153),false);
doAddColor(“gray61”,new Color(156,156,156),false);
doAddColor(“grey61”,new Color(156,156,156),false);
doAddColor(“gray62”,new Color(158,158,158),false);
doAddColor(“grey62”,new Color(158,158,158),false);
doAddColor(“gray63”,new Color(161,161,161),false);
doAddColor(“grey63”,new Color(161,161,161),false);
doAddColor(“gray64”,new Color(163,163,163),false);
doAddColor(“grey64”,new Color(163,163,163),false);
doAddColor(“gray65”,new Color(166,166,166),false);
doAddColor(“grey65”,new Color(166,166,166),false);
doAddColor(“gray66”,new Color(168,168,168),false);
doAddColor(“grey66”,new Color(168,168,168),false);
doAddColor(“gray67”,new Color(171,171,171),false);
doAddColor(“grey67”,new Color(171,171,171),false);
doAddColor(“gray68”,new Color(173,173,173),false);
doAddColor(“grey68”,new Color(173,173,173),false);
doAddColor(“gray69”,new Color(176,176,176),false);
doAddColor(“grey69”,new Color(176,176,176),false);
doAddColor(“gray70”,new Color(179,179,179),false);
doAddColor(“grey70”,new Color(179,179,179),false);
doAddColor(“gray71”,new Color(181,181,181),false);
doAddColor(“grey71”,new Color(181,181,181),false);
doAddColor(“gray72”,new Color(184,184,184),false);
doAddColor(“grey72”,new Color(184,184,184),false);
doAddColor(“gray73”,new Color(186,186,186),false);
doAddColor(“grey73”,new Color(186,186,186),false);
doAddColor(“gray74”,new Color(189,189,189),false);
doAddColor(“grey74”,new Color(189,189,189),false);
doAddColor(“gray75”,new Color(191,191,191),false);
doAddColor(“grey75”,new Color(191,191,191),false);
doAddColor(“gray76”,new Color(194,194,194),false);
doAddColor(“grey76”,new Color(194,194,194),false);
doAddColor(“gray77”,new Color(196,196,196),false);
doAddColor(“grey77”,new Color(196,196,196),false);
doAddColor(“gray78”,new Color(199,199,199),false);
doAddColor(“grey78”,new Color(199,199,199),false);
doAddColor(“gray79”,new Color(201,201,201),false);
doAddColor(“grey79”,new Color(201,201,201),false);
doAddColor(“gray80”,new Color(204,204,204),false);
doAddColor(“grey80”,new Color(204,204,204),false);
doAddColor(“gray81”,new Color(207,207,207),false);
doAddColor(“grey81”,new Color(207,207,207),false);
doAddColor(“gray82”,new Color(209,209,209),false);
doAddColor(“grey82”,new Color(209,209,209),false);
doAddColor(“gray83”,new Color(212,212,212),false);
doAddColor(“grey83”,new Color(212,212,212),false);
doAddColor(“gray84”,new Color(214,214,214),false);
doAddColor(“grey84”,new Color(214,214,214),false);
doAddColor(“gray85”,new Color(217,217,217),false);
doAddColor(“grey85”,new Color(217,217,217),false);
doAddColor(“gray86”,new Color(219,219,219),false);
doAddColor(“grey86”,new Color(219,219,219),false);
doAddColor(“gray87”,new Color(222,222,222),false);
doAddColor(“grey87”,new Color(222,222,222),false);
doAddColor(“gray88”,new Color(224,224,224),false);
doAddColor(“grey88”,new Color(224,224,224),false);
doAddColor(“gray89”,new Color(227,227,227),false);
doAddColor(“grey89”,new Color(227,227,227),false);
doAddColor(“gray90”,new Color(229,229,229),false);
doAddColor(“grey90”,new Color(229,229,229),false);
doAddColor(“gray91”,new Color(232,232,232),false);
doAddColor(“grey91”,new Color(232,232,232),false);
doAddColor(“gray92”,new Color(235,235,235),false);
doAddColor(“grey92”,new Color(235,235,235),false);
doAddColor(“gray93”,new Color(237,237,237),false);
doAddColor(“grey93”,new Color(237,237,237),false);
doAddColor(“gray94”,new Color(240,240,240),false);
doAddColor(“grey94”,new Color(240,240,240),false);
doAddColor(“gray95”,new Color(242,242,242),false);
doAddColor(“grey95”,new Color(242,242,242),false);
doAddColor(“gray96”,new Color(245,245,245),false);
doAddColor(“grey96”,new Color(245,245,245),false);
doAddColor(“gray97”,new Color(247,247,247),false);
doAddColor(“grey97”,new Color(247,247,247),false);
doAddColor(“gray98”,new Color(250,250,250),false);
doAddColor(“grey98”,new Color(250,250,250),false);
doAddColor(“gray99”,new Color(252,252,252),false);
doAddColor(“grey99”,new Color(252,252,252),false);
doAddColor(“gray100”,new Color(255,255,255),false);
doAddColor(“grey100”,new Color(255,255,255),false);
doAddColor(“honeydew”,new Color(240,255,240));
doAddColor(“honeydew1”,new Color(240,255,240),false);
doAddColor(“honeydew2”,new Color(224,238,224),false);
doAddColor(“honeydew3”,new Color(193,205,193),false);
doAddColor(“honeydew4”,new Color(131,139,131),false);
doAddColor(“hotpink”,new Color(255,105,180));
doAddColor(“hotpink1”,new Color(255,110,180),false);
doAddColor(“hotpink2”,new Color(238,106,167),false);
doAddColor(“hotpink3”,new Color(205,96,144),false);
doAddColor(“hotpink4”,new Color(139,58,98),false);
doAddColor(“indianred”,new Color(205,92,92));
doAddColor(“indianred1”,new Color(255,106,106),false);
doAddColor(“indianred2”,new Color(238,99,99),false);
doAddColor(“indianred3”,new Color(205,85,85),false);
doAddColor(“indianred4”,new Color(139,58,58),false);
doAddColor(“indigo”,new Color(75,0,130));
doAddColor(“ivory”,new Color(255,255,240));
doAddColor(“ivory1”,new Color(255,255,240),false);
doAddColor(“ivory2”,new Color(238,238,224),false);
doAddColor(“ivory3”,new Color(205,205,193),false);
doAddColor(“ivory4”,new Color(139,139,131),false);
doAddColor(“khaki”,new Color(240,230,140));
doAddColor(“khaki1”,new Color(255,246,143),false);
doAddColor(“khaki2”,new Color(238,230,133),false);
doAddColor(“khaki3”,new Color(205,198,115),false);
doAddColor(“khaki4”,new Color(139,134,78),false);
doAddColor(“lavender”,new Color(230,230,250));
doAddColor(“lavenderblush”,new Color(255,240,245));
doAddColor(“lavenderblush1”,new Color(255,240,245),false);
doAddColor(“lavenderblush2”,new Color(238,224,229),false);
doAddColor(“lavenderblush3”,new Color(205,193,197),false);
doAddColor(“lavenderblush4”,new Color(139,131,134),false);
doAddColor(“lawngreen”,new Color(124,252,0));
doAddColor(“lemonchiffon”,new Color(255,250,205));
doAddColor(“lemonchiffon1”,new Color(255,250,205),false);
doAddColor(“lemonchiffon2”,new Color(238,233,191),false);
doAddColor(“lemonchiffon3”,new Color(205,201,165),false);
doAddColor(“lemonchiffon4”,new Color(139,137,112),false);
doAddColor(“lightblue”,new Color(173,216,230));
doAddColor(“lightblue1”,new Color(191,239,255),false);
doAddColor(“lightblue2”,new Color(178,223,238),false);
doAddColor(“lightblue3”,new Color(154,192,205),false);
doAddColor(“lightblue4”,new Color(104,131,139),false);
doAddColor(“lightcoral”,new Color(240,128,128));
doAddColor(“lightcyan”,new Color(224,255,255));
doAddColor(“lightcyan1”,new Color(224,255,255),false);
doAddColor(“lightcyan2”,new Color(209,238,238),false);
doAddColor(“lightcyan3”,new Color(180,205,205),false);
doAddColor(“lightcyan4”,new Color(122,139,139),false);
doAddColor(“lightgoldenrod”,new Color(238,221,130));
doAddColor(“lightgoldenrod1”,new Color(255,236,139),false);
doAddColor(“lightgoldenrod2”,new Color(238,220,130),false);
doAddColor(“lightgoldenrod3”,new Color(205,190,112),false);
doAddColor(“lightgoldenrod4”,new Color(139,129,76),false);
doAddColor(“lightgoldenrodyellow”,new Color(250,250,210));
doAddColor(“lightgray”,new Color(211,211,211));
doAddColor(“lightgreen”,new Color(144,238,144));
doAddColor(“lightgrey”,new Color(211,211,211),false);
doAddColor(“lightpink”,new Color(255,182,193));
doAddColor(“lightpink1”,new Color(255,174,185),false);
doAddColor(“lightpink2”,new Color(238,162,173),false);
doAddColor(“lightpink3”,new Color(205,140,149),false);
doAddColor(“lightpink4”,new Color(139,95,101),false);
doAddColor(“lightsalmon”,new Color(255,160,122));
doAddColor(“lightsalmon1”,new Color(255,160,122),false);
doAddColor(“lightsalmon2”,new Color(238,149,114),false);
doAddColor(“lightsalmon3”,new Color(205,129,98),false);
doAddColor(“lightsalmon4”,new Color(139,87,66),false);
doAddColor(“lightseagreen”,new Color(32,178,170));
doAddColor(“lightskyblue”,new Color(135,206,250));
doAddColor(“lightskyblue1”,new Color(176,226,255),false);
doAddColor(“lightskyblue2”,new Color(164,211,238),false);
doAddColor(“lightskyblue3”,new Color(141,182,205),false);
doAddColor(“lightskyblue4”,new Color(96,123,139),false);
doAddColor(“lightslateblue”,new Color(132,112,255));
doAddColor(“lightslategray”,new Color(119,136,153));
doAddColor(“lightslategrey”,new Color(119,136,153),false);
doAddColor(“lightsteelblue”,new Color(176,196,222));
doAddColor(“lightsteelblue1”,new Color(202,225,255),false);
doAddColor(“lightsteelblue2”,new Color(188,210,238),false);
doAddColor(“lightsteelblue3”,new Color(162,181,205),false);
doAddColor(“lightsteelblue4”,new Color(110,123,139),false);
doAddColor(“lightyellow”,new Color(255,255,224));
doAddColor(“lightyellow1”,new Color(255,255,224),false);
doAddColor(“lightyellow2”,new Color(238,238,209),false);
doAddColor(“lightyellow3”,new Color(205,205,180),false);
doAddColor(“lightyellow4”,new Color(139,139,122),false);
doAddColor(“limegreen”,new Color(50,205,50));
doAddColor(“linen”,new Color(250,240,230));
doAddColor(“magenta”,new Color(255,0,255));
doAddColor(“magenta1”,new Color(255,0,255),false);
doAddColor(“magenta2”,new Color(238,0,238),false);
doAddColor(“magenta3”,new Color(205,0,205),false);
doAddColor(“magenta4”,new Color(139,0,139),false);
doAddColor(“maroon”,new Color(176,48,96));
doAddColor(“maroon1”,new Color(255,52,179),false);
doAddColor(“maroon2”,new Color(238,48,167),false);
doAddColor(“maroon3”,new Color(205,41,144),false);
doAddColor(“maroon4”,new Color(139,28,98),false);
doAddColor(“mediumaquamarine”,new Color(102,205,170));
doAddColor(“mediumblue”,new Color(0,0,205));
doAddColor(“mediumorchid”,new Color(186,85,211));
doAddColor(“mediumorchid1”,new Color(224,102,255),false);
doAddColor(“mediumorchid2”,new Color(209,95,238),false);
doAddColor(“mediumorchid3”,new Color(180,82,205),false);
doAddColor(“mediumorchid4”,new Color(122,55,139),false);
doAddColor(“mediumpurple”,new Color(147,112,219));
doAddColor(“mediumpurple1”,new Color(171,130,255),false);
doAddColor(“mediumpurple2”,new Color(159,121,238),false);
doAddColor(“mediumpurple3”,new Color(137,104,205),false);
doAddColor(“mediumpurple4”,new Color(93,71,139),false);
doAddColor(“mediumseagreen”,new Color(60,179,113));
doAddColor(“mediumslateblue”,new Color(123,104,238));
doAddColor(“mediumspringgreen”,new Color(0,250,154));
doAddColor(“mediumturquoise”,new Color(72,209,204));
doAddColor(“mediumvioletred”,new Color(199,21,133));
doAddColor(“midnightblue”,new Color(25,25,112));
doAddColor(“mintcream”,new Color(245,255,250));
doAddColor(“mistyrose”,new Color(255,228,225));
doAddColor(“mistyrose1”,new Color(255,228,225),false);
doAddColor(“mistyrose2”,new Color(238,213,210),false);
doAddColor(“mistyrose3”,new Color(205,183,181),false);
doAddColor(“mistyrose4”,new Color(139,125,123),false);
doAddColor(“moccasin”,new Color(255,228,181));
doAddColor(“navajowhite”,new Color(255,222,173));
doAddColor(“navajowhite1”,new Color(255,222,173),false);
doAddColor(“navajowhite2”,new Color(238,207,161),false);
doAddColor(“navajowhite3”,new Color(205,179,139),false);
doAddColor(“navajowhite4”,new Color(139,121,94),false);
doAddColor(“navy”,new Color(0,0,128));
doAddColor(“navyblue”,new Color(0,0,128),false);
doAddColor(“oldlace”,new Color(253,245,230));
doAddColor(“olivedrab”,new Color(107,142,35));
doAddColor(“olivedrab1”,new Color(192,255,62),false);
doAddColor(“olivedrab2”,new Color(179,238,58),false);
doAddColor(“olivedrab3”,new Color(154,205,50),false);
doAddColor(“olivedrab4”,new Color(105,139,34),false);
doAddColor(“orange”,new Color(255,165,0));
doAddColor(“orange1”,new Color(255,165,0),false);
doAddColor(“orange2”,new Color(238,154,0),false);
doAddColor(“orange3”,new Color(205,133,0),false);
doAddColor(“orange4”,new Color(139,90,0),false);
doAddColor(“orangered”,new Color(255,69,0));
doAddColor(“orangered1”,new Color(255,69,0),false);
doAddColor(“orangered2”,new Color(238,64,0),false);
doAddColor(“orangered3”,new Color(205,55,0),false);
doAddColor(“orangered4”,new Color(139,37,0),false);
doAddColor(“orchid”,new Color(218,112,214));
doAddColor(“orchid1”,new Color(255,131,250),false);
doAddColor(“orchid2”,new Color(238,122,233),false);
doAddColor(“orchid3”,new Color(205,105,201),false);
doAddColor(“orchid4”,new Color(139,71,137),false);
doAddColor(“palegoldenrod”,new Color(238,232,170));
doAddColor(“palegreen”,new Color(152,251,152));
doAddColor(“palegreen1”,new Color(154,255,154),false);
doAddColor(“palegreen2”,new Color(144,238,144),false);
doAddColor(“palegreen3”,new Color(124,205,124),false);
doAddColor(“palegreen4”,new Color(84,139,84),false);
doAddColor(“paleturquoise”,new Color(175,238,238));
doAddColor(“paleturquoise1”,new Color(187,255,255),false);
doAddColor(“paleturquoise2”,new Color(174,238,238),false);
doAddColor(“paleturquoise3”,new Color(150,205,205),false);
doAddColor(“paleturquoise4”,new Color(102,139,139),false);
doAddColor(“palevioletred”,new Color(219,112,147));
doAddColor(“palevioletred1”,new Color(255,130,171),false);
doAddColor(“palevioletred2”,new Color(238,121,159),false);
doAddColor(“palevioletred3”,new Color(205,104,137),false);
doAddColor(“palevioletred4”,new Color(139,71,93),false);
doAddColor(“papayawhip”,new Color(255,239,213));
doAddColor(“peachpuff”,new Color(255,218,185));
doAddColor(“peachpuff1”,new Color(255,218,185),false);
doAddColor(“peachpuff2”,new Color(238,203,173),false);
doAddColor(“peachpuff3”,new Color(205,175,149),false);
doAddColor(“peachpuff4”,new Color(139,119,101),false);
doAddColor(“peru”,new Color(205,133,63));
doAddColor(“pink”,new Color(255,192,203));
doAddColor(“pink1”,new Color(255,181,197),false);
doAddColor(“pink2”,new Color(238,169,184),false);
doAddColor(“pink3”,new Color(205,145,158),false);
doAddColor(“pink4”,new Color(139,99,108),false);
doAddColor(“plum”,new Color(221,160,221));
doAddColor(“plum1”,new Color(255,187,255),false);
doAddColor(“plum2”,new Color(238,174,238),false);
doAddColor(“plum3”,new Color(205,150,205),false);
doAddColor(“plum4”,new Color(139,102,139),false);
doAddColor(“powderblue”,new Color(176,224,230));
doAddColor(“purple”,new Color(160,32,240));
doAddColor(“purple1”,new Color(155,48,255),false);
doAddColor(“purple2”,new Color(145,44,238),false);
doAddColor(“purple3”,new Color(125,38,205),false);
doAddColor(“purple4”,new Color(85,26,139),false);
doAddColor(“red”,new Color(255,0,0));
doAddColor(“red1”,new Color(255,0,0),false);
doAddColor(“red2”,new Color(238,0,0),false);
doAddColor(“red3”,new Color(205,0,0),false);
doAddColor(“red4”,new Color(139,0,0),false);
doAddColor(“rosybrown”,new Color(188,143,143));
doAddColor(“rosybrown1”,new Color(255,193,193),false);
doAddColor(“rosybrown2”,new Color(238,180,180),false);
doAddColor(“rosybrown3”,new Color(205,155,155),false);
doAddColor(“rosybrown4”,new Color(139,105,105),false);
doAddColor(“royalblue”,new Color(65,105,225));
doAddColor(“royalblue1”,new Color(72,118,255),false);
doAddColor(“royalblue2”,new Color(67,110,238),false);
doAddColor(“royalblue3”,new Color(58,95,205),false);
doAddColor(“royalblue4”,new Color(39,64,139),false);
doAddColor(“saddlebrown”,new Color(139,69,19));
doAddColor(“salmon”,new Color(250,128,114));
doAddColor(“salmon1”,new Color(255,140,105),false);
doAddColor(“salmon2”,new Color(238,130,98),false);
doAddColor(“salmon3”,new Color(205,112,84),false);
doAddColor(“salmon4”,new Color(139,76,57),false);
doAddColor(“sandybrown”,new Color(244,164,96));
doAddColor(“seagreen”,new Color(46,139,87));
doAddColor(“seagreen1”,new Color(84,255,159),false);
doAddColor(“seagreen2”,new Color(78,238,148),false);
doAddColor(“seagreen3”,new Color(67,205,128),false);
doAddColor(“seagreen4”,new Color(46,139,87),false);
doAddColor(“seashell”,new Color(255,245,238));
doAddColor(“seashell1”,new Color(255,245,238),false);
doAddColor(“seashell2”,new Color(238,229,222),false);
doAddColor(“seashell3”,new Color(205,197,191),false);
doAddColor(“seashell4”,new Color(139,134,130),false);
doAddColor(“sgiindigo2”,new Color(33,136,104),false);
doAddColor(“sienna”,new Color(160,82,45));
doAddColor(“sienna1”,new Color(255,130,71),false);
doAddColor(“sienna2”,new Color(238,121,66),false);
doAddColor(“sienna3”,new Color(205,104,57),false);
doAddColor(“sienna4”,new Color(139,71,38),false);
doAddColor(“skyblue”,new Color(135,206,235));
doAddColor(“skyblue1”,new Color(135,206,255),false);
doAddColor(“skyblue2”,new Color(126,192,238),false);
doAddColor(“skyblue3”,new Color(108,166,205),false);
doAddColor(“skyblue4”,new Color(74,112,139),false);
doAddColor(“slateblue”,new Color(106,90,205));
doAddColor(“slateblue1”,new Color(131,111,255),false);
doAddColor(“slateblue2”,new Color(122,103,238),false);
doAddColor(“slateblue3”,new Color(105,89,205),false);
doAddColor(“slateblue4”,new Color(71,60,139),false);
doAddColor(“slategray”,new Color(112,128,144));
doAddColor(“slategray1”,new Color(198,226,255),false);
doAddColor(“slategray2”,new Color(185,211,238),false);
doAddColor(“slategray3”,new Color(159,182,205),false);
doAddColor(“slategray4”,new Color(108,123,139),false);
doAddColor(“slategrey”,new Color(112,128,144),false);
doAddColor(“snow”,new Color(255,250,250));
doAddColor(“snow1”,new Color(255,250,250),false);
doAddColor(“snow2”,new Color(238,233,233),false);
doAddColor(“snow3”,new Color(205,201,201),false);
doAddColor(“snow4”,new Color(139,137,137),false);
doAddColor(“springgreen”,new Color(0,255,127));
doAddColor(“springgreen1”,new Color(0,255,127),false);
doAddColor(“springgreen2”,new Color(0,238,118),false);
doAddColor(“springgreen3”,new Color(0,205,102),false);
doAddColor(“springgreen4”,new Color(0,139,69),false);
doAddColor(“steelblue”,new Color(70,130,180));
doAddColor(“steelblue1”,new Color(99,184,255),false);
doAddColor(“steelblue2”,new Color(92,172,238),false);
doAddColor(“steelblue3”,new Color(79,148,205),false);
doAddColor(“steelblue4”,new Color(54,100,139),false);
doAddColor(“tan”,new Color(210,180,140));
doAddColor(“tan1”,new Color(255,165,79),false);
doAddColor(“tan2”,new Color(238,154,73),false);
doAddColor(“tan3”,new Color(205,133,63),false);
doAddColor(“tan4”,new Color(139,90,43),false);
doAddColor(“thistle”,new Color(216,191,216));
doAddColor(“thistle1”,new Color(255,225,255),false);
doAddColor(“thistle2”,new Color(238,210,238),false);
doAddColor(“thistle3”,new Color(205,181,205),false);
doAddColor(“thistle4”,new Color(139,123,139),false);
doAddColor(“tomato”,new Color(255,99,71));
doAddColor(“tomato1”,new Color(255,99,71),false);
doAddColor(“tomato2”,new Color(238,92,66),false);
doAddColor(“tomato3”,new Color(205,79,57),false);
doAddColor(“tomato4”,new Color(139,54,38),false);
doAddColor(“turquoise”,new Color(64,224,208));
doAddColor(“turquoise1”,new Color(0,245,255),false);
doAddColor(“turquoise2”,new Color(0,229,238),false);
doAddColor(“turquoise3”,new Color(0,197,205),false);
doAddColor(“turquoise4”,new Color(0,134,139),false);
doAddColor(“violet”,new Color(238,130,238));
doAddColor(“violetred”,new Color(208,32,144));
doAddColor(“violetred1”,new Color(255,62,150),false);
doAddColor(“violetred2”,new Color(238,58,140),false);
doAddColor(“violetred3”,new Color(205,50,120),false);
doAddColor(“violetred4”,new Color(139,34,82),false);
doAddColor(“wheat”,new Color(245,222,179));
doAddColor(“wheat1”,new Color(255,231,186),false);
doAddColor(“wheat2”,new Color(238,216,174),false);
doAddColor(“wheat3”,new Color(205,186,150),false);
doAddColor(“wheat4”,new Color(139,126,102),false);
doAddColor(“white”,new Color(255,255,255));
doAddColor(“whitesmoke”,new Color(245,245,245));
doAddColor(“yellow”,new Color(255,255,0));
doAddColor(“yellow1”,new Color(255,255,0),false);
doAddColor(“yellow2”,new Color(238,238,0),false);
doAddColor(“yellow3”,new Color(205,205,0),false);
doAddColor(“yellow4”,new Color(139,139,0),false);
doAddColor(“yellowgreen”,new Color(154,205,50));
}
// be sure to specify colors that exist initially in the colorTable
/**
* The default foreground color (black).
*/
public static final Color defaultForeground = getColor(“black”,null);
/**
* The default background color (white).
*/
public static final Color defaultBackground = getColor(“white”,null);
/**
* The default XOR color (light gray).
*/
public static final Color defaultXOR = getColor(“light gray”,null);
/**
* The default font color (black).
*/
public static final Color defaultFontcolor = getColor(“black”,null);
/**
* The default color of last resort in all cases (black).
*/
public static final Color defaultColor = getColor(“black”,null);
/**
* Adds a color to the application color table. For search purposes, names
* are canonicalized by converting to lower case and stripping
* non-alphanumerics. A name must contains at least one alphabetic.
* Once in the table, colors can be set by name, and names can be
* retrieved by color (although a single color referred to by multiple names
* only causes the retrieval of the last name mapped to that color).
*
* @param name the name to be used to reference the color.
* @param color the Color value.
*/
public static void addColor(String name, Color color) throws IllegalArgumentException {
if(name == null || color == null) {
throw new IllegalArgumentException(“supplied name or color is null”);
}
String canonName = canonColor(name, null);
if(canonName == null) {
throw new IllegalArgumentException(“supplied name does not contain alphabetics (” + name + “)”);
}
doAddColor(canonName,color);
}
// performs actual color table puts
private static void doAddColor(String name, Color color, boolean override) {
colorTable.put(name,color);
if(override || colorLookUp.get(color) == null) colorLookUp.put(color,name);
}
// convenience version
private static void doAddColor(String name, Color color) {
doAddColor(name,color,true);
}
// canonicalizes color string (removes non-alphanumeric and lowers case)
private static String canonColor(String name, float[] hsb) {
if(hsb != null) {
hsb[0] = hsb[1] = hsb[2] = -1;
}
if(name == null) return null;
char[] array = name.toCharArray();
int len = 0;
int commas = 0;
int[] commaSpots = new int[3];
int dots = 0;
boolean allDigits = true;
for(int i = 0; i < array.length; i++) {
if(Character.isUpperCase(array[i])) {
array[len++] = Character.toLowerCase(array[i]);
allDigits = false;
} else if(Character.isLowerCase(array[i])) {
array[len++] = array[i];
allDigits = false;
} else if(Character.isDigit(array[i])) {
array[len++] = array[i];
} else if(array[i] == ',') {
if(commas < 2) {
commaSpots[commas] = i;
}
commas++;
array[len++] = array[i];
} else if(array[i] == '.') {
dots++;
array[len++] = array[i];
}
}
if(hsb != null && allDigits && commas == 2 && dots <= 3) {
commaSpots[2] = array.length;
int prev = 0;
try {
for(int i = 0; i < 3; i++) {
hsb[i] = Float.valueOf(name.substring(prev,commaSpots[i])).floatValue();
prev = commaSpots[i] + 1;
}
} catch(NumberFormatException nfe) {
return null;
}
return new String(array,0,len);
}
if(len == 0 || allDigits) return null;
if(commas > 0 || dots > 0) {
int l = len;
len = 0;
for(int i = 0; i < l; i++) {
if(array[i] != '.' && array[i] != ',') {
array[len++] = array[i];
}
}
}
return new String(array,0,len);
}
/**
* Return the color in the color table with the given name.
* If the color is not found, the supplied default is returned.
* If the supplied default is null, the class default is returned.
* If the name consists of three comma or space separated floating
* point numbers in the range 0 to 1 inclusive, then it is assumed
* to represent an HSB color specification and generated directly.
* The name search is case insensitive and looks at alphanumerics only.
*
* @param name the name of the color to be retrieved.
* @param color the color value to return if requested color
* is not found.
*
* @return the color matching the name or the default.
*/
public static Color getColor(String name, Color color) {
if(color == null) color = defaultColor;
if(name == null) return color;
float[] hsb = new float[3];
String canonName = canonColor(name, hsb);
Color retColor = (Color)colorTable.get(canonName);
if(retColor == null) {
if(hsb[0] < 0) {
retColor = color;
} else {
retColor = Color.getHSBColor(hsb[0],hsb[1],hsb[2]);
if(retColor == null) {
retColor = color;
} else {
doAddColor(canonName,retColor);
}
}
}
return retColor;
}
/**
* Return the name of the supplied color.
*
* @param color the color whose name is to be retrieved.
*
* @return the color's (most recently entered) name, if it is in the
* color table, or its HSB value string otherwise.
*/
public static String getColorName(Color color) {
if(color == null) return null;
String name = (String)(colorLookUp.get(color));
if(name == null) {
float[] hsb = Color.RGBtoHSB(color.getRed(),color.getGreen(),color.getBlue(),null);
name = hsb[0]+","+hsb[1]+","+hsb[2];
}
return(name);
}
}
att/grappa/GrappaConstants.java
att/grappa/GrappaConstants.java/*
* This software may only be used by you under license from AT&T Corp.
* ("AT&T"). A copy of AT&T's Source Code Agreement is available at
* AT&T's Internet website having the URL:
*
* If you received this software without first entering into a license
* with AT&T, you have an infringing copy of this software and cannot use
* it without violating AT&T’s intellectual property rights.
*/
package att.grappa;
/**
* This class provides a common set of constant, class variables
* used by the classes in the grappa package.
*
* @version 1.2, 26 May 2005; Copyright 1996 – 2005 by AT&T Corp.
* @author John Mocenigo, Research @ AT&T Labs
*/
public interface GrappaConstants
{
/**
* Package prefix string (“att.grappa.”) if anyone needs it.
*/
public final static String PACKAGE_PREFIX = “att.grappa.”;
/**
* Package name as an up-low string.
*/
public final static String PKG_UPLOW = “Grappa”;
/**
* Package name as an upper-case string (as a convenience).
*/
public final static String PKG_UPPER = “GRAPPA”;
/**
* Package name as an lower-case string (as a convenience).
*/
public final static String PKG_LOWER = “grappa”;
/**
* The new-line string for this system (as specified by the line.spearator property).
*/
public final static String NEW_LINE = System.getProperty(“line.separator”);
/**
* The unicode no-break space character.
*/
public final static char NBSP = ‘\u00a0’;
/**
* The identity transform (as a convenience).
*/
public final static java.awt.geom.AffineTransform IDENTXFRM = new java.awt.geom.AffineTransform();
/*
* edit operations (NOT IMPLEMENTED YET)
public final static int EDIT_UNDO = 0;
public final static int EDIT_CUT = 1;
public final static int EDIT_PASTE = 2;
public final static int EDIT_COPY = 3;
public final static int EDIT_DELETE = 4;
public final static int EDIT_ADD = 5;
*/
/**
* Element type value indicating a node.
*/
public final static int NODE = 1;
/**
* Element type value indicating an edge.
*/
public final static int EDGE = 2;
/**
* Element type value indicating a graph (or subgraph).
*/
public final static int SUBGRAPH = 4;
/**
* System attribute indicator.
*/
final static int SYSTEM = 8;
/**
* Natural log of 10 (as a convenience).
*/
final static double LOG10 = Math.log(10);
/**
* Bit indicator that selection highlight is active.
*/
public final static int SELECTION_MASK = 1;
/**
* Bit indicator that deletion highlight is active.
*/
public final static int DELETION_MASK = 2;
/**
* Bit mask for highlight bits.
*/
public final static int HIGHLIGHT_MASK = SELECTION_MASK|DELETION_MASK;
/**
* Bit indicator that an element should be highlighted.
*/
public final static int HIGHLIGHT_ON = 4;
/**
* Bit indicator that an element should not be highlighted.
*/
public final static int HIGHLIGHT_OFF = 8;
/**
* Bit indicator that an element’s highlight should be toggled.
*/
public final static int HIGHLIGHT_TOGGLE = 16;
/**
* Maximum number of bits needed to represet the Element types.
* Element type is merged with the element id number (a sequentially
* assigned number) to ensure a unique identifier (within an invocation of
* the package).
*
*/
public final static int TYPES_SHIFT = 3;
/**
* Points per inch (72).
*/
public final static double PointsPerInch = 72;
/**
* Default gap in pixels between peripheries.
*/
public final static int PERIPHERY_GAP = 4;
/**
* Name prefix for name generation of unnamed subgraphs.
*/
public final static String ANONYMOUS_PREFIX = “_anonymous_”;
/**
* String name for bounding box attribute (bb).
*/
public final static String BBOX_ATTR = “bb”;
/**
* String name for cluster rank attribute (clusterrank).
*/
public final static String CLUSTERRANK_ATTR = “clusterrank”;
/**
* String name for color attribute (color).
*/
public final static String COLOR_ATTR = “color”;
/**
* String name for custom class used to draw custom shapes (custom).
*/
public final static String CUSTOM_ATTR = “custom”;
/**
* String name for direction attribute (dir).
*/
public final static String DIR_ATTR = “dir”;
/**
* String name for distortion attribute (distortion).
*/
public final static String DISTORTION_ATTR = “distortion”;
/**
* String name for fill color attribute (fillcolor).
*/
public final static String FILLCOLOR_ATTR = “fillcolor”;
/**
* String name for fontcolor attribute (fontcolor).
*/
public final static String FONTCOLOR_ATTR = “fontcolor”;
/**
* String name for fontname attribute (fontname).
*/
public final static String FONTNAME_ATTR = “fontname”;
/**
* String name for fontsize attribute (fontsize).
*/
public final static String FONTSIZE_ATTR = “fontsize”;
/**
* String name for fontstyle attribute (fontstyle).
*/
public final static String FONTSTYLE_ATTR = “fontstyle”;
/**
* String name for background color attribute (grappaBackgroundColor).
*/
public final static String GRAPPA_BACKGROUND_COLOR_ATTR = Grappa.PKG_LOWER+”BackgroundColor”;
/**
* String name for selection color attribute (grappaSelectionColor).
*/
public final static String GRAPPA_SELECTION_STYLE_ATTR = Grappa.PKG_LOWER+”SelectionColor”;
/**
* String name for deletion color attribute (grappaDeletionColor).
*/
public final static String GRAPPA_DELETION_STYLE_ATTR = Grappa.PKG_LOWER+”DeletionColor”;
/**
* String name for fontsize adjustment attribute (grappaFontsizeAdjustment).
*/
public final static String GRAPPA_FONTSIZE_ADJUSTMENT_ATTR = Grappa.PKG_LOWER+”FontsizeAdjustment”;
/**
* String name for height attribute (height).
*/
public final static String HEIGHT_ATTR = “height”;
/**
* String name for image attribute (image).
*/
public final static String IMAGE_ATTR = “image”;
/**
* String name for label attribute (label).
*/
public final static String LABEL_ATTR = “label”;
/**
* String name for label position attribute (lp).
*/
public final static String LP_ATTR = “lp”;
/**
* String name for head label attribute (headlabel).
*/
public final static String HEADLABEL_ATTR = “headlabel”;
/**
* String name for head label position attribute (head_lp).
*/
public final static String HEADLP_ATTR = “head_lp”;
/**
* String name for tail label attribute (taillabel).
*/
public final static String TAILLABEL_ATTR = “taillabel”;
/**
* String name for tail label position attribute (tail_lp).
*/
public final static String TAILLP_ATTR = “tail_lp”;
/**
* String name for label position attribute (margin).
*/
public final static String MARGIN_ATTR = “margin”;
/**
* String name for mincross limit attribute [unused] (mclimit).
*/
public final static String MCLIMIT_ATTR = “mclimit”;
/**
* String name for minimum subgraph bounding box attribute (minbox).
*/
public final static String MINBOX_ATTR = “minbox”;
/**
* String name for minimum rank distance between head and tail of edges attribute [unused] (minlen).
*/
public final static String MINLEN_ATTR = “minlen”;
/**
* String name for minimum subgraph size attribute (minsize).
*/
public final static String MINSIZE_ATTR = “minsize”;
/**
* String name for node separation attribute [unused] (nodesep).
*/
public final static String NODESEP_ATTR = “nodesep”;
/**
* String name for orientation angle attribute (orientation).
*/
public final static String ORIENTATION_ATTR = “orientation”;
/**
* String name for patch work attribute (patch).
*/
public final static String PATCH_ATTR = “patch”;
/**
* String name for peripheries attribute (peripheries).
*/
public final static String PERIPHERIES_ATTR = “peripheries”;
/**
* String name for position attribute (pos).
*/
public final static String POS_ATTR = “pos”;
/**
* String name for print list attribute (printlist).
*/
public final static String PRINTLIST_ATTR = “printlist”;
/**
* String name for rank direction attribute [unused] (rankdir).
*/
public final static String RANKDIR_ATTR = “rankdir”;
/**
* String name for rank separation attribute [unused] (ranksep)
*/
public final static String RANKSEP_ATTR = “ranksep”;
/**
* String name for rectangles attribute (rects).
*/
public final static String RECTS_ATTR = “rects”;
/**
* String name for rotation attribute (rotation).
*/
public final static String ROTATION_ATTR = “rotation”;
/**
* String name for shape attribute (shape).
*/
public final static String SHAPE_ATTR = “shape”;
/**
* String name for sides attribute (sides).
*/
public final static String SIDES_ATTR = “sides”;
/**
* String name for size attribute [unused] (size).
*/
public final static String SIZE_ATTR = “size”;
/**
* String name for skew attribute (skew).
*/
public final static String SKEW_ATTR = “skew”;
/**
* String name for style attribute (style).
*/
public final static String STYLE_ATTR = “style”;
/**
* String name for tag attribute (tag).
*/
public final static String TAG_ATTR = “tag”;
/**
* String name for tip attribute (tip).
*/
public final static String TIP_ATTR = “tip”;
/**
* String name for weight attribute [unused] (weight).
*/
public final static String WEIGHT_ATTR = “weight”;
/**
* String name for width attribute (width).
*/
public final static String WIDTH_ATTR = “width”;
/**
* Hash code for bounding box attribute (bb).
*/
public final static int BBOX_HASH = BBOX_ATTR.hashCode();
/**
* Hash code for color attribute (color).
*/
public final static int COLOR_HASH = COLOR_ATTR.hashCode();
/**
* Hash code for custom attribute (custom).
*/
public final static int CUSTOM_HASH = CUSTOM_ATTR.hashCode();
/**
* Hash code for edge direction attribute (dir).
*/
public final static int DIR_HASH = DIR_ATTR.hashCode();
/**
* Hash code for distortion attribute (distortion).
*/
public final static int DISTORTION_HASH = DISTORTION_ATTR.hashCode();
/**
* Hash code for fillcolor attribute (fillcolor).
*/
public final static int FILLCOLOR_HASH = FILLCOLOR_ATTR.hashCode();
/**
* Hash code for fontcolor attribute (fontcolor).
*/
public final static int FONTCOLOR_HASH = FONTCOLOR_ATTR.hashCode();
/**
* Hash code for fontname attribute (fontname).
*/
public final static int FONTNAME_HASH = FONTNAME_ATTR.hashCode();
/**
* Hash code for fontsize attribute (fontsize).
*/
public final static int FONTSIZE_HASH = FONTSIZE_ATTR.hashCode();
/**
* Hash code for fontstyle attribute (fontstyle).
*/
public final static int FONTSTYLE_HASH = FONTSTYLE_ATTR.hashCode();
/**
* Hash code for background color attribute (grappaBackgroundColor).
*/
public final static int GRAPPA_BACKGROUND_COLOR_HASH = GRAPPA_BACKGROUND_COLOR_ATTR.hashCode();
/**
* Hash code for selection color attribute (grappaSelectionColor).
*/
public final static int GRAPPA_SELECTION_STYLE_HASH = GRAPPA_SELECTION_STYLE_ATTR.hashCode();
/**
* Hash code for deletion color attribute (grappaDeletionColor).
*/
public final static int GRAPPA_DELETION_STYLE_HASH = GRAPPA_DELETION_STYLE_ATTR.hashCode();
/**
* Hash code for fontsize adjustment attribute (grappaFontsizeAdjustment).
*/
public final static int GRAPPA_FONTSIZE_ADJUSTMENT_HASH = GRAPPA_FONTSIZE_ADJUSTMENT_ATTR.hashCode();
/**
* Hash code for height attribute (height).
*/
public final static int HEIGHT_HASH = HEIGHT_ATTR.hashCode();
/**
* Hash code for image attribute (image).
*/
public final static int IMAGE_HASH = IMAGE_ATTR.hashCode();
/**
* Hash code for label attribute (label).
*/
public final static int LABEL_HASH = LABEL_ATTR.hashCode();
/**
* Hash code for label position attribute (lp).
*/
public final static int LP_HASH = LP_ATTR.hashCode();
/**
* Hash code for head label attribute (headlabel).
*/
public final static int HEADLABEL_HASH = HEADLABEL_ATTR.hashCode();
/**
* Hash code for head label position attribute (head_lp).
*/
public final static int HEADLP_HASH = HEADLP_ATTR.hashCode();
/**
* Hash code for tail label attribute (taillabel).
*/
public final static int TAILLABEL_HASH = TAILLABEL_ATTR.hashCode();
/**
* Hash code for tail label position attribute (tail_lp).
*/
public final static int TAILLP_HASH = TAILLP_ATTR.hashCode();
/**
* Hash code for margin attribute (margin).
*/
public final static int MARGIN_HASH = MARGIN_ATTR.hashCode();
/**
* Hash code for mincross limit attribute (mclimit).
*/
public final static int MCLIMIT_HASH = MCLIMIT_ATTR.hashCode();
/**
* Hash code for minimum subgraph bounding box attribute (minbox).
*/
public final static int MINBOX_HASH = MINBOX_ATTR.hashCode();
/**
* Hash code for minimum rank distance between head and tail of edges attribute (minlen).
*/
public final static int MINLEN_HASH = MINLEN_ATTR.hashCode();
/**
* Hash code for minimum subgraph size attribute (minsize).
*/
public final static int MINSIZE_HASH = MINSIZE_ATTR.hashCode();
/**
* Hash code for node separation attribute (nodesep).
*/
public final static int NODESEP_HASH = NODESEP_ATTR.hashCode();
/**
* Hash code for orientation attribute (orientation).
*/
public final static int ORIENTATION_HASH = ORIENTATION_ATTR.hashCode();
/**
* Hash code for patch work attribute (patch).
*/
public final static int PATCH_HASH = PATCH_ATTR.hashCode();
/**
* Hash code for peripheries attribute (peripheries).
*/
public final static int PERIPHERIES_HASH = PERIPHERIES_ATTR.hashCode();
/**
* Hash code for position attribute (pos).
*/
public final static int POS_HASH = POS_ATTR.hashCode();
/**
* Hash code for rank direction attribute (rankdir).
*/
/**
* Hash code for print list attribute (printlist).
*/
public final static int PRINTLIST_HASH = PRINTLIST_ATTR.hashCode();
public final static int RANKDIR_HASH = RANKDIR_ATTR.hashCode();
/**
* Hash code for rank separation attribute (ranksep).
*/
public final static int RANKSEP_HASH = RANKSEP_ATTR.hashCode();
/**
* Hash code for rectangles attribute (rects).
*/
public final static int RECTS_HASH = RECTS_ATTR.hashCode();
/**
* Hash code for rotation attribute (rotation).
*/
public final static int ROTATION_HASH = ROTATION_ATTR.hashCode();
/**
* Hash code for shape attribute (shape).
*/
public final static int SHAPE_HASH = SHAPE_ATTR.hashCode();
/**
* Hash code for sides attribute (sides).
*/
public final static int SIDES_HASH = SIDES_ATTR.hashCode();
/**
* Hash code for size attribute (size).
*/
public final static int SIZE_HASH = SIZE_ATTR.hashCode();
/**
* Hash code for skew attribute (skew).
*/
public final static int SKEW_HASH = SKEW_ATTR.hashCode();
/**
* Hash code for style attribute (style).
*/
public final static int STYLE_HASH = STYLE_ATTR.hashCode();
/**
* Hash code for tag attribute (tag).
*/
public final static int TAG_HASH = TAG_ATTR.hashCode();
/**
* Hash code for tip attribute (tip).
*/
public final static int TIP_HASH = TIP_ATTR.hashCode();
/**
* Hash code for weight attribute (weight).
*/
public final static int WEIGHT_HASH = WEIGHT_ATTR.hashCode();
/**
* Hash code for width attribute (width).
*/
public final static int WIDTH_HASH = WIDTH_ATTR.hashCode();
//
// Attribute types
//
/**
* Indicator that no attribute value type is specified.
* When no attribute type is specified, an error results.
*/
public final static int _NO_TYPE = 0x00;
/**
* Indicator that attribute value is an instance of GrappaBox.
*/
public final static int BOX_TYPE = 0x01;
/**
* Indicator that attribute value is an instance of java.awt.Color.
*/
public final static int COLOR_TYPE = 0x02;
/**
* Indicator that attribute value is an instance of java.lang.Integer representing an edge direction.
*/
public final static int DIR_TYPE = 0x03;
/**
* Indicator that attribute value is an instance of java.lang.Double.
*/
public final static int DOUBLE_TYPE = 0x04;
/**
* Indicator that attribute value is a java.lang.Integer representing a font style.
*/
public final static int FONTSTYLE_TYPE = 0x05;
/**
* Indicator that attribute value is a java.lang.Hashtable whose keys provide a list of values
*/
public final static int HASHLIST_TYPE = 0x06;
/**
* Indicator that attribute value is an instance of java.lang.Integer.
*/
public final static int INTEGER_TYPE = 0x07;
/**
* Indicator that attribute value is an instance of GrappaLine.
*/
public final static int LINE_TYPE = 0x08;
/**
* Indicator that attribute value is an instance of GrappaPoint.
*/
public final static int POINT_TYPE = 0x09;
/**
* Indicator that attribute value is a java.lang.Integer representing a Grappa shape.
*/
public final static int SHAPE_TYPE = 0x0A;
/**
* Indicator that attribute value is an instance of GrappaSize.
*/
public final static int SIZE_TYPE = 0x0B;
/**
* Indicator that attribute value is an instance of java.lang.String.
*/
public final static int STRING_TYPE = 0x0C;
/**
* Indicator that attribute value is an instance of GrappaStyle.
*/
public final static int STYLE_TYPE = 0x0D;
/*
* The indicators used to define the underlying Shape of this object.
*/
/**
* Indicator that a valid shape was not specified for a graph element.
*/
public final static int NO_SHAPE = 0;
/**
* Indicator that the element has a line shape.
*/
public final static int LINE_SHAPE = 1;
/**
* Indicator that the element has a box shape.
*/
public final static int BOX_SHAPE = 2;
/**
* Indicator that the element has a diamond shape.
*/
public final static int DIAMOND_SHAPE = 3;
/**
* Indicator that the element has a double circle shape.
*/
public final static int DOUBLECIRCLE_SHAPE = 4;
/**
* Indicator that the element has a double octagon shape.
*/
public final static int DOUBLEOCTAGON_SHAPE = 5;
/**
* Indicator that the element has a egg shape.
*/
public final static int EGG_SHAPE = 6;
/**
* Indicator that the element has a hexagon shape.
*/
public final static int HEXAGON_SHAPE = 7;
/**
* Indicator that the element has a house shape.
*/
public final static int HOUSE_SHAPE = 8;
/**
* Indicator that the element has a upside-down house shape.
*/
public final static int INVERTEDHOUSE_SHAPE = 9;
/**
* Indicator that the element has a upside-down trapezium shape.
*/
public final static int INVERTEDTRAPEZIUM_SHAPE = 10;
/**
* Indicator that the element has a upside-down triangle shape.
*/
public final static int INVERTEDTRIANGLE_SHAPE = 11;
/**
* Indicator that the element has a octagon shape.
*/
public final static int OCTAGON_SHAPE = 12;
/**
* Indicator that the element has a oval shape.
*/
public final static int OVAL_SHAPE = 13;
/**
* Indicator that the element has a parallelogram shape.
*/
public final static int PARALLELOGRAM_SHAPE = 14;
/**
* Indicator that the element has a pentagon shape.
*/
public final static int PENTAGON_SHAPE = 15;
/**
* Indicator that the element has no shape, but rather is just a text label.
*/
public final static int PLAINTEXT_SHAPE = 16;
/**
* Indicator that the element has a general polygonal shape.
*/
public final static int POINT_SHAPE = 17;
/**
* Indicator that the element has a general polygonal shape.
*/
public final static int POLYGON_SHAPE = 18;
/**
* Indicator that the element has a record shape.
* A record shape is of a box shape that contains one or more labelled
* sub-partitions within it.
*/
public final static int RECORD_SHAPE = 19;
/**
* Indicator that the element has a box shape with rounded corners.
*/
public final static int ROUNDEDBOX_SHAPE = 20;
/**
* Indicator that the element has a trapezium shape.
*/
public final static int TRAPEZIUM_SHAPE = 21;
/**
* Indicator that the element has a triangle shape.
*/
public final static int TRIANGLE_SHAPE = 22;
/**
* Indicator that the element has a triple octagon shape.
*/
public final static int TRIPLEOCTAGON_SHAPE = 23;
/**
* Indicator that the element has a circular shape with parallel chords top and bottom.
*/
public final static int MCIRCLE_SHAPE = 24;
/**
* Indicator that the element has a diamond shape with triangles inset in each corner.
*/
public final static int MDIAMOND_SHAPE = 25;
/**
* Indicator that the element has a record shape with triangles inset in each of its four outer corners.
*/
public final static int MRECORD_SHAPE = 26;
/**
* Indicator that the element has a square shape with triangles inset in each of its corners.
*/
public final static int MSQUARE_SHAPE = 27;
/**
* Indicator that the element shape is determined by a user-supplied class defined by the “custom” attribute
*/
public final static int CUSTOM_SHAPE = 28;
// or’ed with others shape types
/**
* Bit mask for extracting shape information.
*/
public final static int SHAPE_MASK = 1023;
/**
* Bit flag indicating that the shape path needs to be generated by
* by Grappa rather than relying on Java built-ins.
*/
public final static int GRAPPA_SHAPE = 1024;
}
att/grappa/GrappaLine.java
att/grappa/GrappaLine.java/*
* This software may only be used by you under license from AT&T Corp.
* (“AT&T”). A copy of AT&T’s Source Code Agreement is available at
* AT&T’s Internet website having the URL:
*
* If you received this software without first entering into a license
* with AT&T, you have an infringing copy of this software and cannot use
* it without violating AT&T’s intellectual property rights.
*/
package att.grappa;
import java.awt.*;
import java.awt.geom.*;
/**
* This class provides line and bezier-curve support for Grappa.
*
* @version 1.2, 26 May 2005; Copyright 1996 – 2005 by AT&T Corp.
* @author John Mocenigo, Research @ AT&T Labs
*/
public class GrappaLine
implements
GrappaConstants,
Cloneable, Shape
{
/**
* Arrow head length
*/
public final static double arrowLength = 10;
/**
* Arrow head width
*/
public final static double arrowWidth = 5;
/**
* Bit flag to indicate that line has no arrow heads.
*/
public static final int NONE_ARROW_EDGE = 0;
/**
* Bit flag to indicate that line has an arrow head at its head end.
*/
public static final int HEAD_ARROW_EDGE = 1;
/**
* Bit flag to indicate that line has an arrow head at its tail end.
*/
public static final int TAIL_ARROW_EDGE = 2;
/**
* Bit flag to indicate that line has arrow heads at both ends.
* Note that
* NONE_ARROW_EDGE + HEAD_ARROW_EDGE + TAIL_ARROW_EDGE = BOTH_ARROW_EDGE
*/
public static final int BOTH_ARROW_EDGE = 3;
// the general path describing this line (including arrow heads)
private GeneralPath path = null;
// fatter path for contains and intersects tests
private GeneralPath testpath = null;
// arrow head info
private int arrow = NONE_ARROW_EDGE;
// the point set for this line (not including arrow heads)
private GrappaPoint[] gpts = null;
// fix winding rule at instantiation time
private int windingRule = Grappa.windingRule;
////////////////////////////////////////////////////////////////////////
//
// Constructors
//
////////////////////////////////////////////////////////////////////////
/**
* Constructs a new GrappaLine
object from an array of
* (cubic) curve points.
* The winding rule for this path is defaulted (from Grappa.windingRule).
* @param pts the GrappaPoint
array used to describe the curve
* @param type indicates arrow type (NONE_ARROW_EDGE,HEAD_ARROW_EDGE,
* TAIL_ARROW_EDGE,BOTH_ARROW_EDGE)
*/
public GrappaLine(GrappaPoint[] pts, int type) {
updateLine(pts,type);
}
/**
* Constructs a new GrappaLine
object from a string of
* (cubic) curve points as used by “dot”.
* All of the initial geometry and the winding rule for this path are
* defaulted.
* @param curve the String
that specifies the point list; the
* format is: [s,x0,y0|e,xN,yN] [x1,y2] … [xN-1,yN-1]
*/
public GrappaLine(String curve) {
updateLine(curve);
}
////////////////////////////////////////////////////////////////////////
//
// Public methods
//
////////////////////////////////////////////////////////////////////////
/**
* Check for equality of this object with the supplied object.
*
* @param the object to be checked for equality
* @return true, when equal
*/
public boolean equals(Object obj) {
if(obj == null || !(obj instanceof GrappaLine)) return(false);
GrappaLine cmp = (GrappaLine)obj;
if(cmp == this) return(true);
if(cmp.getArrowType() != arrow) return(false);
if(cmp.gpts.length != gpts.length || !gpts.equals(cmp.gpts)) return(false);
// should be sufficient, should be no need to compare path
//if(!path.equals(cmp.path)) return(false);
return(true);
}
/**
* Return the arrow type for this line.
* @return one of NONE_ARROW_EDGE,HEAD_ARROW_EDGE, TAIL_ARROW_EDGE, or BOTH_ARROW_EDGE
*/
public int getArrowType() {
return arrow;
}
/**
* Return the winding rule for this line.
* @return one of WIND_NON_ZERO or WIND_EVEN_ODD
*/
public int getWindingRule() {
return windingRule;
}
/**
* Check is the line is oriented away from the given point.
*
* @return true if the line is oriented so that its starting point is
* nearer to the supplied point than its ending point.
*/
public boolean startsNear(Point2D pt) {
return(gpts[0].distance(pt) < gpts[gpts.length-1].distance(pt));
}
/**
* Provides a string representation of this object consistent
* with Grappa attributes.
*
* @return attribute-suitable string representation of this GrappaLine.
*/
public String toAttributeString() {
return(toFormattedString("%p"));
}
/**
* Provides a formatted string representation of this object.
*
* @param pointFormat the specific format directive to use for each point in the line (%p is the base directive).
* @return a string representation of this GrappaLine.
*/
public String toFormattedString(String pointFormat) {
int ps = 0;
int pe = gpts.length – 1;
boolean spacer = false;
StringBuffer buf = new StringBuffer();
if((arrow&HEAD_ARROW_EDGE) != 0) {
buf.append(“s,”);
buf.append(gpts[ps++].toFormattedString(pointFormat));
spacer = true;
}
if((arrow&TAIL_ARROW_EDGE) != 0) {
if(spacer) {
buf.append(” e,”);
} else {
buf.append(“e,”);
spacer = true;
}
buf.append(gpts[pe–].toFormattedString(pointFormat));
}
while(ps <= pe) {
if(spacer) {
buf.append(" ");
} else {
spacer = true;
}
buf.append(gpts[ps++].toFormattedString(pointFormat));
}
return(buf.toString());
}
/**
* Provides a generic string representation of this object.
*
* @return a generic string representation of this GrappaLine.
*/
public String toString() {
int ps = 0;
int pe = gpts.length - 1;
boolean spacer = false;
StringBuffer buf = new StringBuffer();
if((arrow&HEAD_ARROW_EDGE) != 0) {
buf.append("s,");
buf.append(gpts[ps].x);
buf.append(",");
buf.append(gpts[ps++].y);
spacer = true;
}
if((arrow&TAIL_ARROW_EDGE) != 0) {
if(spacer) {
buf.append(" e,");
} else {
buf.append("e,");
spacer = true;
}
buf.append(gpts[pe].x);
buf.append(",");
buf.append(gpts[pe--].y);
}
while(ps <= pe) {
if(spacer) {
buf.append(" ");
} else {
spacer = true;
}
buf.append(gpts[ps].x);
buf.append(",");
buf.append(gpts[ps++].y);
}
return(buf.toString());
}
/**
* Changes the arrow type for this line.
*
* @param new_type indicates arrow type (NONE_ARROW_EDGE,HEAD_ARROW_EDGE,
* TAIL_ARROW_EDGE,BOTH_ARROW_EDGE)
*
* @return true if the type changed, false otherwise.
*/
public boolean changeArrowType(int new_type) {
boolean changed = false;
if(arrow != new_type && (new_type&(~(BOTH_ARROW_EDGE))) == 0) {
changed = true;
updateLine(gpts, new_type);
}
return(changed);
}
////////////////////////////////////////////////////////////////////////
//
// Private methods
//
////////////////////////////////////////////////////////////////////////
// add an arrow to the path of this line
private void addArrow(GeneralPath path, GeneralPath testpath, GrappaPoint tip, GrappaPoint shaft, double length, double width) {
double theta = Math.atan2((tip.y - shaft.y), (tip.x - shaft.x));
double half_width = width / 2.0;
float x, y;
path.lineTo(
x = (float) (tip.x - (length * Math.cos(theta) - half_width * Math.sin(theta))),
y = (float) (tip.y - (length * Math.sin(theta) + half_width * Math.cos(theta)))
);
testpath.lineTo(x,y);
path.lineTo(
x = (float) (tip.x - (length * Math.cos(theta) + half_width * Math.sin(theta))),
y = (float) (tip.y - (length * Math.sin(theta) - half_width * Math.cos(theta)))
);
testpath.lineTo(x,y);
path.lineTo(
x = (float) tip.x,
y = (float) tip.y
);
testpath.lineTo(x,y);
}
// translate the supplied string into the points of this line
private void updateLine(String curve) {
int type = NONE_ARROW_EDGE;
int i, j, k;
int len = curve.length();
int pts = 1;
boolean wasSpace = true;
GrappaPoint[] grpts = null;
Integer attr_type;
// first pass is mostly sizing and basic validity check
for(i = 0, j = len; i < len; i++) {
switch((int)curve.charAt(i)) {
case 's':
wasSpace = false;
type += HEAD_ARROW_EDGE;
break;
case 'e':
wasSpace = false;
type += TAIL_ARROW_EDGE;
break;
case ' ':
if(!wasSpace) {
if(j == len) j = i; // first space (used later)
pts++;
wasSpace = true;
}
break;
default:
wasSpace = false;
break;
}
}
if(wasSpace) pts--;
if(pts < 2 || type > BOTH_ARROW_EDGE) {
throw new IllegalArgumentException(“bad curve specifier string (” + curve + “)”);
}
grpts = new GrappaPoint[pts];
for(i = 0; i < len; i++) {
if(curve.charAt(i) != ' ') {
break;
}
}
pts = 0;
if(curve.charAt(i) == 's') {
grpts[pts++] = new GrappaPoint(curve.substring(i+2,j));
for(i = ++j; i < len; i++) {
if(curve.charAt(i) != ' ') {
break;
}
}
for(k = j, j = len; k < j; k++) {
if(curve.charAt(k) == ' ') {
j = k;
break;
}
}
}
if(curve.charAt(i) == 'e') {
grpts[grpts.length-1] = new GrappaPoint(curve.substring(i+2,j));
for(i = ++j; i < len; i++) {
if(curve.charAt(i) != ' ') {
break;
}
}
for(k = j, j = len; k < j; k++) {
if(curve.charAt(k) == ' ') {
j = k;
break;
}
}
}
if(curve.charAt(i) == 's') {
grpts[pts++] = new GrappaPoint(curve.substring(i+2,j));
for(i = ++j; i < len; i++) {
if(curve.charAt(i) != ' ') {
break;
}
}
for(k = j, j = len; k < j; k++) {
if(curve.charAt(k) == ' ') {
j = k;
break;
}
}
}
while(i < len) {
grpts[pts++] = new GrappaPoint(curve.substring(i,j));
for(i = ++j; i < len; i++) {
if(curve.charAt(i) != ' ') {
break;
}
}
for(k = j, j = len; k < j; k++) {
if(curve.charAt(k) == ' ') {
j = k;
break;
}
}
}
updateLine(grpts, type);
}
// given points and an arrow type, generate the path of this line
private void updateLine(GrappaPoint[] grpts, int type) {
int pts = 0;
int xpts = 0;
float x, y, x2, y2, x3, y3, z = -2;
if((type&HEAD_ARROW_EDGE) != 0) xpts += 3;
if((type&TAIL_ARROW_EDGE) != 0) xpts += 3;
GeneralPath grpath = new GeneralPath(windingRule, grpts.length+xpts+grpts.length-1);
GeneralPath grtestpath = new GeneralPath(windingRule, grpts.length+xpts+grpts.length-1);
if(grpts.length < 2) {
throw new IllegalArgumentException("need at least two supplied points");
}
grpath.moveTo(x = (float)grpts[pts].x, y = (float)grpts[pts++].y);
grtestpath.moveTo(x+z,y+z);
if((type&HEAD_ARROW_EDGE) != 0) {
grtestpath.moveTo(x+z,y+z);
addArrow(grpath, grtestpath, grpts[pts-1], grpts[pts], arrowLength, arrowWidth);
grpath.lineTo(x = (float)grpts[pts].x, y = (float)grpts[pts++].y);
grtestpath.lineTo(x-z, y-z);
} else grtestpath.lineTo(x-z,y-z);
boolean lastWasLine = false;
while(pts < grpts.length) {
lastWasLine = false;
if(pts+3 <= grpts.length) {
grpath.curveTo(
x = (float)grpts[pts].x, y = (float)grpts[pts++].y,
x2 = (float)grpts[pts].x, y2 = (float)grpts[pts++].y,
x3 = (float)grpts[pts].x, y3 = (float)grpts[pts++].y
);
grtestpath.curveTo(x-z,y-z,x2-z,y2-z,x3-z,y3-z);
} else {
lastWasLine = true;
grpath.lineTo(x = (float)grpts[pts].x, y = (float)grpts[pts++].y);
grtestpath.lineTo(x-z,y-z);
}
}
if((type&TAIL_ARROW_EDGE) != 0) {
addArrow(grpath, grtestpath, grpts[pts-1], grpts[pts-2], arrowLength, arrowWidth);
}
pts--;
while(pts > 0) {
if(!lastWasLine && pts-3 >= 0) {
grpath.curveTo(
x = (float)grpts[–pts].x, y = (float)grpts[pts].y,
x2 = (float)grpts[–pts].x, y2 = (float)grpts[pts].y,
x3 = (float)grpts[–pts].x, y3 = (float)grpts[pts].y
);
grtestpath.curveTo(x+z,y+z,x2+z,y2+z,x3+z,y3+z);
} else {
lastWasLine = false;
grpath.lineTo(x = (float)grpts[–pts].x, y = (float)grpts[pts].y);
grtestpath.lineTo(x+z,y+z);
}
}
this.gpts = grpts;
this.path = grpath;
this.testpath = grtestpath;
this.arrow = type;
}
////////////////////////////////////////////////////////////////////////
//
// Cloneable interface
//
////////////////////////////////////////////////////////////////////////
/**
* Creates a new object of the same class as this object.
*
* @return a clone of this instance.
* @exception OutOfMemoryError if there is not enough memory.
* @see java.lang.Cloneable
*/
public Object clone() {
try {
GrappaLine copy = (GrappaLine) super.clone();
copy.path = (GeneralPath) path.clone();
if(gpts != null) {
copy.gpts = (GrappaPoint[])(gpts.clone());
}
return copy;
} catch (CloneNotSupportedException e) {
// this shouldn’t happen, since we are Cloneable
throw new InternalError();
}
}
////////////////////////////////////////////////////////////////////////
//
// Shape interface
//
////////////////////////////////////////////////////////////////////////
public final boolean contains(double x, double y) {
return(testpath.contains(x, y));
}
public final boolean contains(double x, double y, double width, double height) {
return(testpath.contains(x, y, width, height));
}
public final boolean contains(Point2D p) {
return(testpath.contains(p));
}
public final boolean contains(Rectangle2D r) {
return(testpath.contains(r));
}
public final Rectangle getBounds() {
return(path.getBounds2D().getBounds());
}
public final Rectangle2D getBounds2D() {
return(path.getBounds2D());
}
/**
* Equivalent to getPathIterator(null).
*
* @see getPathIterator(AffineTransform)
*/
public final PathIterator getPathIterator() {
return path.getPathIterator(null);
}
public final PathIterator getPathIterator(AffineTransform at) {
return path.getPathIterator(at);
}
public final PathIterator getPathIterator(AffineTransform at, double flatness) {
return new FlatteningPathIterator(path.getPathIterator(at), flatness);
}
public final boolean intersects(double x, double y, double width, double height) {
return(testpath.intersects(x, y, width, height));
}
public final boolean intersects(Rectangle2D r) {
return(testpath.intersects(r));
}
}
att/grappa/GrappaListener.java
att/grappa/GrappaListener.java/*
* This software may only be used by you under license from AT&T Corp.
* (“AT&T”). A copy of AT&T’s Source Code Agreement is available at
* AT&T’s Internet website having the URL:
*
* If you received this software without first entering into a license
* with AT&T, you have an infringing copy of this software and cannot use
* it without violating AT&T’s intellectual property rights.
*/
package att.grappa;
/**
* An interface for handling mouse-related activity that occurs on a graph.
*
* @version 1.2, 26 May 2005; Copyright 1996 – 2005 by AT&T Corp.
* @author John Mocenigo, Research @ AT&T Labs
*/
public interface GrappaListener
{
/**
* The method called when a single mouse click occurs on a displayed subgraph.
*
* @param subg displayed subgraph where action occurred
* @param elem subgraph element in which action occurred
* @param pt the point where the action occurred (graph coordinates)
* @param modifiers mouse modifiers in effect
* @param panel specific panel where the action occurred
*/
public void grappaClicked(Subgraph subg, Element elem, GrappaPoint pt, int modifiers, int clickCount, GrappaPanel panel);
/**
* The method called when a mouse press occurs on a displayed subgraph.
*
* @param subg displayed subgraph where action occurred
* @param elem subgraph element in which action occurred
* @param pt the point where the action occurred (graph coordinates)
* @param modifiers mouse modifiers in effect
* @param panel specific panel where the action occurred
*/
public void grappaPressed(Subgraph subg, Element elem, GrappaPoint pt, int modifiers, GrappaPanel panel);
/**
* The method called when a mouse release occurs on a displayed subgraph.
*
* @param subg displayed subgraph where action occurred
* @param elem subgraph element in which action occurred
* @param pt the point where the action occurred (graph coordinates)
* @param modifiers mouse modifiers in effect
* @param pressedElem subgraph element in which the most recent mouse press occurred
* @param pressedPt the point where the most recent mouse press occurred (graph coordinates)
* @param pressedModifiers mouse modifiers in effect when the most recent mouse press occurred
* @param outline enclosing box specification from the previous drag position (for XOR reset purposes)
* @param panel specific panel where the action occurred
*/
public void grappaReleased(Subgraph subg, Element elem, GrappaPoint pt, int modifiers, Element pressedElem, GrappaPoint pressedPt, int pressedModifiers, GrappaBox outline, GrappaPanel panel);
/**
* The method called when a mouse drag occurs on a displayed subgraph.
*
* @param subg displayed subgraph where action occurred
* @param currentPt the current drag point
* @param currentModifiers the current drag mouse modifiers
* @param pressedElem subgraph element in which the most recent mouse press occurred
* @param pressedPt the point where the most recent mouse press occurred (graph coordinates)
* @param pressedModifiers mouse modifiers in effect when the most recent mouse press occurred
* @param outline enclosing box specification from the previous drag position (for XOR reset purposes)
* @param panel specific panel where the action occurred
*/
public void grappaDragged(Subgraph subg, GrappaPoint currentPt, int currentModifiers, Element pressedElem, GrappaPoint pressedPt, int pressedModifiers, GrappaBox outline, GrappaPanel panel);
/**
* The method called when a element tooltip is needed.
*
* @param subg displayed subgraph where action occurred
* @param elem subgraph element in which action occurred
* @param pt the point where the action occurred (graph coordinates)
* @param modifiers mouse modifiers in effect
* @param panel specific panel where the action occurred
*
* @return the tip to be displayed or null
*/
public String grappaTip(Subgraph subg, Element elem, GrappaPoint pt, int modifiers, GrappaPanel panel);
}
att/grappa/GrappaNexus.java
att/grappa/GrappaNexus.java/*
* This software may only be used by you under license from AT&T Corp.
* (“AT&T”). A copy of AT&T’s Source Code Agreement is available at
* AT&T’s Internet website having the URL:
*
* If you received this software without first entering into a license
* with AT&T, you have an infringing copy of this software and cannot use
* it without violating AT&T’s intellectual property rights.
*/
package att.grappa;
import java.lang.reflect.*;
import java.awt.*;
import java.awt.geom.*;
import java.awt.image.*;
import java.net.*;
import java.util.Observer;
import java.util.Hashtable;
/**
* This class brings together shape, text and attribute information
* related to bounding and drawing an element.
*
* @version 1.2, 26 May 2005; Copyright 1996 – 2005 by AT&T Corp.
* @author John Mocenigo, Research @ AT&T Labs
*/
public class GrappaNexus
implements
GrappaConstants,
Cloneable, ImageObserver, Observer, Shape
{
/**
* RoundRectangle arc height factor
*/
public static double arcHeightFactor = 0.05;
/**
* RoundRectangle arc width factor
*/
public static double arcWidthFactor = 0.05;
Area textArea = null;
Shape shape = null;
int shapeType = NO_SHAPE;
Rectangle2D bbox = null;
GrappaStyle style = null;
Color fillcolor = null;
Color color = null;
Image image = null;
boolean imageLoading = false;
boolean dirty = false; // just for cluster subgraphs, now
Stroke stroke = null;
// used for RECORD_SHAPE/MRECORD_SHAPE only, so far
private Object[] objs = null;
// used when SHAPE_ATTR is CUSTOM_SHAPE
private Object custom_shape = null;
/**
* Indicates if element text should be included in the element
* bounding box. By default, it is.
*
* @see Grappa#shapeBoundText
*/
public boolean boundText = true;
/**
* Indicates if the area bounding the element text should be
* filled/outlined along with the element when being drawn.
* By default, it is not.
*
* @see Grappa#shapeClearText
*/
public boolean clearText = false;
/**
* Indicates if element text should be drawn when drawing the
* element. By default, it is.
*
* @see Grappa#shapeDrawText
*/
public boolean drawText = true;
Element element = null;
long lastUpdate = 0;
private long lastShapeUpdate = 0;
private long lastTextUpdate = 0;
private long lastStyleUpdate = 0;
private long lastDecorationUpdate = 0;
private long lastImageUpdate = 0;
Font font = null;
String[] lstr = null;
GrappaPoint[] lpos = null;
Color font_color = null;
// fix winding rule at instantiation time
private int windingRule = Grappa.windingRule;
////////////////////////////////////////////////////////////////////////
//
// Constructors
//
////////////////////////////////////////////////////////////////////////
/**
* Constructs a new GrappaNexus
object from an element.
* @param elem the Element
needing a GrappaNexus
object.
*/
public GrappaNexus(Element elem) {
this.element = elem;
rebuild();
}
////////////////////////////////////////////////////////////////////////
//
// Public methods
//
////////////////////////////////////////////////////////////////////////
/**
* Get the underlying element.
*
* @return the element underlying this GrappaNexus.
*/
public Element getElement() {
return element;
}
/**
* Return the image, if any, loaded for this element
* @return an image or null
*/
public Image getImage() {
return image;
}
/**
* Return status of image loading.
* Returns true whenever an image has begun loading for this
* element, but has not yet completed.
*
* @return true, during image loading; false, otherwise
*/
public boolean isImageLoading() {
return imageLoading;
}
/**
* Return the winding rule for this line.
* @return one of WIND_NON_ZERO or WIND_EVEN_ODD
*/
public int getWindingRule() {
return windingRule;
}
/**
* Recompute the components of this GrappaNexus.
*
* @see updateStyle
* @see updateDecoration
* @see updateShape
* @see updateText
* @see updateImage
*/
public void rebuild() {
updateStyle();
updateDecoration();
updateShape();
updateText();
updateImage();
}
/**
* Update the shape information for the underlying element.
* For nodes, the distortion, height, orientation, peripheries, pos, rotation, shape, sides, skew and width attributes are examined.
* For edges, the pos attribute is examined.
* For subgraph, the bounding box is recomputed.
*/
public void updateShape() {
long thisShapeUpdate = System.currentTimeMillis();
switch(element.getType()) {
case NODE:
// re-initialize some values
custom_shape = null;
objs = null;
if(element.getSubgraph().isCluster() && element.getSubgraph().grappaNexus != null)
element.getSubgraph().grappaNexus.dirty = true;
Node node = (Node)element;
GrappaPoint pos = (GrappaPoint)node.getAttributeValue(POS_ATTR);
Double Width = (Double)node.getAttributeValue(WIDTH_ATTR);
Double Height = (Double)node.getAttributeValue(HEIGHT_ATTR);
Integer Type = (Integer)node.getAttributeValue(SHAPE_ATTR);
double width = PointsPerInch * Width.doubleValue();
double height = PointsPerInch * Height.doubleValue();
int type = Type.intValue();
// the above attributes are sure to be there since they are defaulted,
// but these could return null values, so be sure to account for that
Integer Peripheries = (Integer)node.getAttributeValue(PERIPHERIES_ATTR);
Integer Sides = (Integer)node.getAttributeValue(SIDES_ATTR);
Double Distortion = (Double)node.getAttributeValue(DISTORTION_ATTR);
Double Skew = (Double)node.getAttributeValue(SKEW_ATTR);
Double Orientation = (Double)node.getAttributeValue(ORIENTATION_ATTR);
Double Rotation = (Double)node.getAttributeValue(ROTATION_ATTR);
int peripheries = Peripheries == null ? -1 : Peripheries.intValue();
int sides = Sides == null ? -1 : Sides.intValue();
double distortion = Distortion == null ? 0 : Distortion.doubleValue();
double skew = Skew == null ? 0 : Skew.doubleValue();
double orientation = Orientation == null ? 0 : Orientation.doubleValue();
double rotation = Rotation == null ? 0 : Rotation.doubleValue();
if(Orientation != null && orientation != 0 && Grappa.orientationInDegrees) {
orientation = Math.PI * orientation / 180.0;
}
GeneralPath path;
switch(type) {
case CUSTOM_SHAPE:
String custom = (String)node.getAttributeValue(CUSTOM_ATTR);
if(custom == null) {
throw new IllegalArgumentException(“custom attibuted null for node (” + node.getName() + “) with custom shape”);
}
Class custom_class;
try {
custom_class = Class.forName(custom);
}
catch(Exception e) {
throw new IllegalArgumentException(“custom class unavailable for custom shape ‘” + custom + “‘”);
}
if(!(GrappaShape.class.isAssignableFrom(custom_class))) {
throw new IllegalArgumentException(“custom class ‘” + custom + “‘ does not extend the GrappaShape class”);
}
Constructor ccustom;
try {
ccustom= custom_class.getConstructor(new Class[] { Element.class, double.class, double.class, double.class, double.class });
}
catch(Exception e) {
throw new IllegalArgumentException(“constructor for custom class shape ‘” + custom + “‘ not found”);
}
try {
if(Grappa.centerPointNodes) {
shape = (Shape)(custom_shape = ccustom.newInstance(new Object[] { node, new Double(pos.x – (width/2.0)), new Double(pos.y – (height/2.0)), new Double(width), new Double(height) }));
} else {
shape = (Shape)(custom_shape = ccustom.newInstance(new Object[] { node, new Double(pos.x), new Double(pos.y), new Double(width), new Double(height) }));
}
}
catch(Exception e) {
if(e instanceof InvocationTargetException) {
Throwable t = ((InvocationTargetException)e).getTargetException();
Grappa.displayException((Exception)t);
} else if(e instanceof UndeclaredThrowableException) {
throw new IllegalArgumentException(“cannot instantiate custom shape ‘” + custom + “‘ for node ‘” + node.getName() + “‘ because2: ” + ((UndeclaredThrowableException)e).getUndeclaredThrowable().getMessage());
} else {
throw new IllegalArgumentException(“cannot instantiate custom shape ‘” + custom + “‘ for node ‘” + node.getName() + “‘ because3: ” + e.getMessage());
}
}
shapeType = CUSTOM_SHAPE;
break;
case BOX_SHAPE:
if(
(Distortion == null || distortion == 0)
&&
(Skew == null || skew == 0)
&&
(Orientation == null || orientation == 0)
) {
shapeType = BOX_SHAPE;
if(Grappa.centerPointNodes) {
shape = new Rectangle2D.Double(pos.x – (width/2.0), pos.y – (height/2.0), width, height);
} else {
shape = new Rectangle2D.Double(pos.x, pos.y, width, height);
}
if(Peripheries != null && peripheries > 1) {
path = new GeneralPath(shape);
for(int i = 1; i < peripheries; i++) {
if(Grappa.centerPointNodes) {
path.append
(
new Rectangle2D.Double
(
(pos.x - width/2.0) + (double)(i * PERIPHERY_GAP),
(pos.y - height/2.0) + (double)(i * PERIPHERY_GAP),
width - (double)(2 * i * PERIPHERY_GAP),
height - (double)(2 * i * PERIPHERY_GAP)
),
false
);
} else {
path.append
(
new Rectangle2D.Double
(
pos.x + (double)(i * PERIPHERY_GAP),
pos.y + (double)(i * PERIPHERY_GAP),
width - (double)(2 * i * PERIPHERY_GAP),
height - (double)(2 * i * PERIPHERY_GAP)
),
false
);
}
}
shape = path;
}
} else {
shapeType = BOX_SHAPE|GRAPPA_SHAPE;
if(Grappa.centerPointNodes) {
shape = new GrappaShape(shapeType, pos.x, pos.y, width, height, sides, peripheries, distortion, skew, orientation, style.rounded, style.diagonals, null);
} else {
shape = new GrappaShape(shapeType, pos.x + (width/2.0), pos.y + (height/2.0), width, height, sides, peripheries, distortion, skew, orientation, style.rounded, style.diagonals, null);
}
}
break;
case ROUNDEDBOX_SHAPE:
if(
(Distortion == null || distortion == 0)
&&
(Skew == null || skew == 0)
&&
(Orientation == null || orientation == 0)
) {
shapeType = ROUNDEDBOX_SHAPE;
if(Grappa.centerPointNodes) {
shape = new RoundRectangle2D.Double(pos.x - (width/2.0), pos.y - (height/2.0), width, height, arcWidthFactor * width, arcHeightFactor * height);
} else {
shape = new RoundRectangle2D.Double(pos.x, pos.y, width, height, arcWidthFactor * width, arcHeightFactor * height);
}
if(Peripheries != null && peripheries > 1) {
path = new GeneralPath(shape);
for(int i = 1; i < peripheries; i++) {
if(Grappa.centerPointNodes) {
path.append
(
new RoundRectangle2D.Double
(
(pos.x - width/2.0) + (double)(i * PERIPHERY_GAP),
(pos.y - height/2.0) + (double)(i * PERIPHERY_GAP),
width - (double)(2 * i * PERIPHERY_GAP),
height - (double)(2 * i * PERIPHERY_GAP),
arcWidthFactor * (width - (double)(2 * i * PERIPHERY_GAP)),
arcHeightFactor * (height - (double)(2 * i * PERIPHERY_GAP))
),
false
);
} else {
path.append
(
new RoundRectangle2D.Double
(
pos.x + (double)(i * PERIPHERY_GAP),
pos.y + (double)(i * PERIPHERY_GAP),
width - (double)(2 * i * PERIPHERY_GAP),
height - (double)(2 * i * PERIPHERY_GAP),
arcWidthFactor * (width - (double)(2 * i * PERIPHERY_GAP)),
arcHeightFactor * (height - (double)(2 * i * PERIPHERY_GAP))
),
false
);
}
}
shape = path;
}
} else {
shapeType = ROUNDEDBOX_SHAPE|GRAPPA_SHAPE;
if(Grappa.centerPointNodes) {
shape = new GrappaShape(shapeType, pos.x, pos.y, width, height, sides, peripheries, distortion, skew, orientation, style.rounded, style.diagonals, null);
} else {
shape = new GrappaShape(shapeType, pos.x + (width/2.0), pos.y + (height/2.0), width, height, sides, peripheries, distortion, skew, orientation, style.rounded, style.diagonals, null);
}
}
break;
case OVAL_SHAPE:
if(
(Distortion == null || distortion == 0)
&&
(Skew == null || skew == 0)
&&
(Orientation == null || orientation == 0)
) {
shapeType = OVAL_SHAPE;
if(Grappa.centerPointNodes) {
shape = new Ellipse2D.Double(pos.x - (width/2.0), pos.y - (height/2.0), width, height);
} else {
shape = new Ellipse2D.Double(pos.x, pos.y, width, height);
}
if(Peripheries != null && peripheries > 1) {
path = new GeneralPath(shape);
for(int i = 1; i < peripheries; i++) {
if(Grappa.centerPointNodes) {
path.append
(
new Ellipse2D.Double
(
(pos.x - width/2.0) + (double)(i * PERIPHERY_GAP),
(pos.y - height/2.0) + (double)(i * PERIPHERY_GAP),
width - (double)(2 * i * PERIPHERY_GAP),
height - (double)(2 * i * PERIPHERY_GAP)
),
false
);
} else {
path.append
(
new Ellipse2D.Double
(
pos.x + (double)(i * PERIPHERY_GAP),
pos.y + (double)(i * PERIPHERY_GAP),
width - (double)(2 * i * PERIPHERY_GAP),
height - (double)(2 * i * PERIPHERY_GAP)
),
false
);
}
}
shape = path;
}
} else {
shapeType = OVAL_SHAPE|GRAPPA_SHAPE;
if(Grappa.centerPointNodes) {
shape = new GrappaShape(shapeType, pos.x, pos.y, width, height, sides, peripheries, distortion, skew, orientation, style.rounded, style.diagonals, null);
} else {
shape = new GrappaShape(shapeType, pos.x + (width/2.0), pos.y + (height/2.0), width, height, sides, peripheries, distortion, skew, orientation, style.rounded, style.diagonals, null);
}
}
break;
case DIAMOND_SHAPE:
case DOUBLECIRCLE_SHAPE:
case DOUBLEOCTAGON_SHAPE:
case EGG_SHAPE:
case HEXAGON_SHAPE:
case HOUSE_SHAPE:
case INVERTEDHOUSE_SHAPE:
case INVERTEDTRAPEZIUM_SHAPE:
case INVERTEDTRIANGLE_SHAPE:
case OCTAGON_SHAPE:
case PARALLELOGRAM_SHAPE:
case PENTAGON_SHAPE:
case PLAINTEXT_SHAPE:
case POINT_SHAPE:
case POLYGON_SHAPE:
case TRAPEZIUM_SHAPE:
case TRIANGLE_SHAPE:
case TRIPLEOCTAGON_SHAPE:
case MCIRCLE_SHAPE:
case MDIAMOND_SHAPE:
case MSQUARE_SHAPE:
shapeType = type|GRAPPA_SHAPE;
if(Grappa.centerPointNodes) {
shape = new GrappaShape(shapeType, pos.x, pos.y, width, height, sides, peripheries, distortion, skew, orientation, style.rounded, style.diagonals, null);
} else {
shape = new GrappaShape(shapeType, pos.x + (width/2.0), pos.y + (height/2.0), width, height, sides, peripheries, distortion, skew, orientation, style.rounded, style.diagonals, null);
}
break;
case RECORD_SHAPE:
case MRECORD_SHAPE:
shapeType = type|GRAPPA_SHAPE;
objs = GrappaSupportRects.parseRecordInfo(node);
String rects = null;
if(objs != null)
rects = (String)(objs[2]);
if(Grappa.centerPointNodes) {
shape = new GrappaShape(shapeType, pos.x, pos.y, width, height, sides, peripheries, distortion, skew, orientation, style.rounded, style.diagonals, rects);
} else {
shape = new GrappaShape(shapeType, pos.x + (width/2.0), pos.y + (height/2.0), width, height, sides, peripheries, distortion, skew, orientation, style.rounded, style.diagonals, rects);
}
break;
default:
throw new IllegalArgumentException("unsupported type for this constructor (" + type + ")");
}
// handle rotation (rotation just spins the node,
// orientation spins it within a fixed bounding box
if(Rotation != null && rotation != 0 && shape != null) {
double theta = rotation;
if(Grappa.rotationInDegrees) {
theta = Math.PI * theta / 180.0;
}
if(Grappa.centerPointNodes)
shape = AffineTransform.getRotateInstance(theta,pos.x,pos.y).createTransformedShape(shape);
else
shape = AffineTransform.getRotateInstance(theta,pos.x+(width/2.0),pos.y+(height/2.0)).createTransformedShape(shape);
}
break;
case EDGE:
Edge edge = (Edge)element;
shapeType = LINE_SHAPE;
if(element.getSubgraph().isCluster() && element.getSubgraph().grappaNexus != null)
element.getSubgraph().grappaNexus.dirty = true;
if((shape = (Shape)edge.getAttributeValue(POS_ATTR)) == null) {
Integer attr_type = (Integer)(edge.getAttributeValue(DIR_ATTR));
edge.direction = (attr_type != null ? attr_type.intValue() : (edge.getGraph().isDirected()?GrappaLine.TAIL_ARROW_EDGE:GrappaLine.NONE_ARROW_EDGE));
// create a default straight line connecting the two
// node centers
edge.setAttribute(
"pos",
new GrappaLine(new GrappaPoint[] { (GrappaPoint)(edge.getTail().getAttributeValue(POS_ATTR)), (GrappaPoint)(edge.getHead().getAttributeValue(POS_ATTR)) }, edge.direction)
);
shape = (Shape)edge.getAttributeValue(POS_ATTR);
}
break;
case SUBGRAPH:
Subgraph subgraph = (Subgraph)element;
shapeType = BOX_SHAPE;
dirty = false;
// cannot call subgraph.getBoundingBox() because it would recurse,
// so just put the guts here
Rectangle2D sgbox = null;
Element elem = null;
GraphEnumeration enm = subgraph.elements();
while(enm.hasMoreElements()) {
elem = enm.nextGraphElement();
if(elem == element) continue;
switch(elem.getType()) {
case Grappa.NODE:
case Grappa.EDGE:
elem.buildShape();
if(sgbox == null) {
sgbox = elem.grappaNexus.getBounds2D();
} else {
sgbox.add(elem.grappaNexus.rawBounds2D());
}
break;
case Grappa.SUBGRAPH:
if(sgbox == null) {
sgbox = ((Subgraph)elem).getBoundingBox();
} else {
sgbox.add(((Subgraph)elem).getBoundingBox());
}
break;
default: // cannot happen
throw new InternalError("unknown type (" + elem.getType() + ")");
}
}
GrappaSize minSize = (GrappaSize)element.getAttributeValue(MINSIZE_ATTR);
if(minSize != null) {
if(sgbox == null) {
sgbox = new java.awt.geom.Rectangle2D.Double(0,0,minSize.getWidth(),minSize.getHeight());
} else {
sgbox.add(new java.awt.geom.Rectangle2D.Double(sgbox.getCenterX()-(minSize.getWidth()/2.0),sgbox.getCenterY()-(minSize.getHeight()/2.0),minSize.getWidth(),minSize.getHeight()));
}
}
GrappaBox minBox = (GrappaBox)element.getAttributeValue(MINBOX_ATTR);
if(minBox != null) {
if(sgbox == null) {
sgbox = new java.awt.geom.Rectangle2D.Double(minBox.x,minBox.y,minBox.width,minBox.height);
} else {
sgbox.add(new java.awt.geom.Rectangle2D.Double(minBox.x,minBox.y,minBox.width,minBox.height));
}
}
if(sgbox == null) {
sgbox = new java.awt.geom.Rectangle2D.Double(0,0,0,0);
}
shape = sgbox;
break;
default:
throw new IllegalArgumentException("unrecognized element type (" + element.getType() + ") for " + element.getName());
}
bboxCheckSet();
lastUpdate = lastShapeUpdate = thisShapeUpdate;
}
/**
* Update the shape information for the underlying element.
* The style attribute is examined.
*/
public void updateStyle() {
long thisStyleUpdate = System.currentTimeMillis();
if((style = (GrappaStyle)element.getAttributeValue(STYLE_ATTR)) == null) {
throw new InternalError(“style defaults not properly set in Graph.java”);
}
// an attempt to handle font info passed via style instead of fontstyle
if(
style.font_style != null
&&
style.font_style != (Integer)element.getAttributeValue(FONTSTYLE_ATTR)
) {
element.setAttribute(FONTSTYLE_ATTR,style.font_style);
style.font_style = null;
}
lastUpdate = lastStyleUpdate = thisStyleUpdate;
}
/**
* Update the text information for the underlying element.
* The fontcolor, fontname, fontsize, fontstyle, and label attributes are examined.
* The lp attribute is also examined for edges and subgraphs.
*/
public void updateText() {
String[] tstr = null;
GrappaPoint[] tpos = null;
Area area = null;
Font tfont = null;
boolean makeAdjustment = false;
double signum = -1;
int offset = 0;
String headstr, tailstr;
GrappaPoint headpt, tailpt;
int lcnt = 0;
boolean hasEdgeLabel = false;
Attribute attr = null;
long thisTextUpdate = System.currentTimeMillis();
String[] labels;
GrappaPoint[] lps;
String labelAttr = (String)element.getAttributeValue(LABEL_ATTR);
if(labelAttr != null && labelAttr.equals(“\\N”))
labelAttr = element.getName();
if(labelAttr != null && labelAttr.length() > 0) {
lcnt++;
} else labelAttr = null;
headstr = tailstr = null;
headpt = tailpt = null;
if (element.isEdge()) {
if ((headstr = (String)element.getAttributeValue(HEADLABEL_ATTR)) != null && (attr = element.getLocalAttribute(HEADLP_ATTR)) != null) {
headpt = (GrappaPoint)(attr.getValue());
lcnt++;
hasEdgeLabel = true;
} else headstr = null;
if ((tailstr = (String)element.getAttributeValue(TAILLABEL_ATTR)) != null && (attr = element.getLocalAttribute(TAILLP_ATTR)) != null) {
tailpt = (GrappaPoint)(attr.getValue());
lcnt++;
hasEdgeLabel = true;
} else tailstr = null;
}
// all string attributes are trimmed when they are stored
// if(labelAttr != null)
// labelAttr = labelAttr.trim();
if(labelAttr != null || hasEdgeLabel) {
if(
element.isNode()
&&
(
shapeType == (RECORD_SHAPE|GRAPPA_SHAPE)
||
shapeType == (MRECORD_SHAPE|GRAPPA_SHAPE)
)
&&
labelAttr.indexOf(‘|’) < 0
&&
labelAttr.indexOf('{') == 0
&&
labelAttr.lastIndexOf('}') == labelAttr.length() - 1
) {
labelAttr = labelAttr.substring(1,labelAttr.length()-1).trim();
}
if(hasEdgeLabel || labelAttr.length() > 0) {
String fontname = (String)element.getAttributeValue(FONTNAME_ATTR);
Integer fontstyle = (Integer)element.getAttributeValue(FONTSTYLE_ATTR);
Integer fontsize = (Integer)element.getAttributeValue(FONTSIZE_ATTR);
Integer fontadj = (Integer)(element.getGraph()).getGrappaAttributeValue(GRAPPA_FONTSIZE_ADJUSTMENT_ATTR);
// set font
tfont = new Font(fontname,fontstyle.intValue(),fontsize.intValue() + fontadj.intValue());
String rectString = null;
int lines;
int i;
char[] array;
int[] justification;
Rectangle2D[] bnds;
java.awt.font.LineMetrics[] mtrc;
int start;
char ch;
String str;
double wdinfo, htinfo;
double top;
double x;
if(
element.isNode()
&&
(
shapeType == (RECORD_SHAPE|GRAPPA_SHAPE)
||
shapeType == (MRECORD_SHAPE|GRAPPA_SHAPE)
)
&&
labelAttr.indexOf(‘|’) >= 0
) {
if(objs == null)
updateShape();
if(objs != null && objs[0] != null && objs[1] != null) {
labels = (String[])objs[0];
lps = (GrappaPoint[])objs[1];
} else {
labels = new String[1];
labels[0] = labelAttr;
lps = new GrappaPoint[1];
lps[0] = ((Node)element).getCenterPoint();
}
} else {
Subgraph sg;
labels = new String[lcnt];
lps = new GrappaPoint[lcnt];
lcnt = 0;
if (labelAttr != null)
labels[lcnt++] = labelAttr;
if (headstr != null) {
labels[lcnt] = headstr;
lps[lcnt] = headpt;
lcnt++;
}
if (tailstr != null) {
labels[lcnt] = tailstr;
lps[lcnt] = tailpt;
}
if (labelAttr != null) {
if(Grappa.autoPositionNodeLabel && element.isNode()) {
lps[0] = ((Node)element).getCenterPoint();
} else if((attr = element.getLocalAttribute(LP_ATTR)) == null || ((sg = element.getSubgraph()) != null && attr == sg.getLocalAttribute(LP_ATTR))) {
Rectangle2D lbox;
if((lbox = (Rectangle2D)element.getAttributeValue(BBOX_ATTR)) == null) {
lbox = bbox;
}
if(element.isSubgraph() && lbox != null) {
lps[0] = new GrappaPoint(lbox.getX() + lbox.getWidth()/2.0, (Grappa.labelGraphBottom?lbox.getMaxY():lbox.getMinY()));
element.setAttribute(LP_ATTR, lps[0].clone());
} else {
lps[0] = null;
}
} else {
lps[0] = (GrappaPoint)(attr.getValue());
}
if(element.isSubgraph() && attr == null) {
if(Grappa.labelGraphBottom) {
signum = 1;
} else {
signum = -1;
}
makeAdjustment = true;
}
}
}
for(int l = 0; l < labels.length; l++) { if(labels[l] != null && lps[l] != null && labels[l].length() > 0) {
if(labels[l].equals(“\\N”)) {
labels[l] = element.getName();
if(labels[l] == null) continue;
}
// break label into multiple lines as indicated by line-breaks
lines = 1;
array = labels[l].toCharArray();
// first count lines
for(i=0; i
//htinfo += bnds[lines].getHeight();
htinfo += 2 + tfont.getSize();
if(ch == ‘l’) justification[lines++] = -1;
else if(ch == ‘r’) justification[lines++] = 1;
else justification[lines++] = 0;
start = (i+1);
}
}
if(start < array.length) {
tstr[offset+lines] = new String(array,start,array.length - start);
bnds[lines] = tfont.getStringBounds(tstr[offset+lines],element.getGraph().REFCNTXT);
mtrc[lines] = tfont.getLineMetrics(tstr[offset+lines],element.getGraph().REFCNTXT);
if(bnds[lines].getWidth() > wdinfo) wdinfo = bnds[lines].getWidth();
//htinfo += bnds[lines].getHeight();
htinfo += 2 + tfont.getSize();
if(ch == ‘l’) justification[lines] = -1;
else if(ch == ‘r’) justification[lines] = 1;
else justification[lines] = 0;
}
//htinfo += mtrc[lines].getLeading();
//htinfo += (mtrc[lines].getLeading()) * tfont.getSize2D() / mtrc[lines].getHeight();
if(makeAdjustment) {
if(Grappa.labelGraphOutside) {
lps[l].y += signum * htinfo;
} else {
lps[l].y -= signum * htinfo;
}
}
// half these as that’s how they will be used
wdinfo /= 2.0;
htinfo /= 2.0;
// figure out textArea and positioning of each line of text
// doing it now instead of at rendering time means some
// approximation, but text rendering is iffy anyway and this
// will be close enough and more efficient (if you call this
// efficient)
// first, find top of text bounding box
top = lps[l].y – htinfo;
// now, for each line:
// 1. determine left-side position and create (add to) textArea
// 2. getAscent() to determine actually draw position
// 3. shift down hieght of line
x = 0;
for(i = 0; i < bnds.length; i++) {
if(justification[i] < 0) {
// left
x = lps[l].x - wdinfo;
} else if(justification[i] > 0) {
// right
x = lps[l].x + wdinfo – bnds[i].getWidth();
} else {
x = lps[l].x – bnds[i].getWidth()/2.0;
}
bnds[i].setRect(x,top,bnds[i].getWidth(),bnds[i].getHeight());
if(area == null) {
area = new Area(bnds[i]);
} else {
area.add(new Area(bnds[i]));
}
//tpos[offset+i] = new GrappaPoint(x, top + mtrc[i].getAscent());
//tpos[offset+i] = new GrappaPoint(x, top + Math.ceil((mtrc[i].getAscent()+mtrc[i].getLeading())*tfont.getSize()/mtrc[i].getHeight()));
tpos[offset+i] = new GrappaPoint(x, top + tfont.getSize() – 1);
//top += bnds[i].getHeight();
top += 2 + tfont.getSize();
}
}
}
}
}
// commit changes
font = tfont;
lpos = tpos;
lstr = tstr;
textArea = area;
bboxCheckSet();
lastUpdate = lastTextUpdate = thisTextUpdate;
}
/**
* Update the decoration information for the underlying element.
* The color and fontcolor attributes are examined.
* For edges, the dir attribute is examined.
*/
public void updateDecoration() {
long thisDecorationUpdate = System.currentTimeMillis();
color = (Color)(element.getAttributeValue(COLOR_ATTR));
fillcolor = (Color)(element.getAttributeValue(FILLCOLOR_ATTR));
font_color = (Color)(element.getAttributeValue(FONTCOLOR_ATTR));
if(element.isEdge() && shape != null && shape instanceof GrappaLine) {
Edge edge = (Edge)element;
int graph_dir = edge.getGraph().isDirected() ? GrappaLine.TAIL_ARROW_EDGE : GrappaLine.NONE_ARROW_EDGE;
int dir = graph_dir;
Integer attr_type = (Integer)(edge.getThisAttributeValue(DIR_ATTR));
if(attr_type != null)
dir = attr_type.intValue();
edge.direction = dir;
GrappaLine gline = (GrappaLine)shape;
boolean forward = gline.startsNear((Point2D)(edge.getTail().getAttributeValue(POS_ATTR)));
// basically, it edge loops on same node, assume it is always
// in the forward orientation
if(!forward && edge.getHead() == edge.getTail())
forward = true;
int line_dir;
if(forward) {
line_dir = gline.getArrowType();
} else {
switch(gline.getArrowType()) {
case GrappaLine.HEAD_ARROW_EDGE:
line_dir = GrappaLine.TAIL_ARROW_EDGE;
case GrappaLine.TAIL_ARROW_EDGE:
line_dir = GrappaLine.HEAD_ARROW_EDGE;
break;
default:
line_dir = gline.getArrowType();
break;
}
}
if(line_dir != dir) {
if(forward) {
line_dir = dir;
} else {
switch(dir) {
case GrappaLine.HEAD_ARROW_EDGE:
line_dir = GrappaLine.TAIL_ARROW_EDGE;
case GrappaLine.TAIL_ARROW_EDGE:
line_dir = GrappaLine.HEAD_ARROW_EDGE;
break;
default:
line_dir = dir;
break;
}
}
gline.changeArrowType(line_dir);
edge.setAttribute(POS_ATTR, gline);
}
}
lastUpdate = lastDecorationUpdate = thisDecorationUpdate;
}
/**
* Update the image information for the underlying element.
*/
public void updateImage() {
long thisImageUpdate = System.currentTimeMillis();
String path = (String)(element.getAttributeValue(IMAGE_ATTR));
if(path != null && Grappa.toolkit != null) {
this.image = null;
imageLoading = true;
Image raw_image = null;
try {
URL url = new URL(path);
raw_image = Grappa.toolkit.getImage(url);
}
catch(Exception ex) {}
if(raw_image == null) {
try {
raw_image = Grappa.toolkit.getImage(path);
}
catch(Exception ex) {}
}
if(raw_image != null) {
if(Grappa.toolkit.prepareImage(raw_image,-1,-1,this)) {
this.image = raw_image;
imageLoading = false;
}
} else {
imageLoading = false;
}
} else {
this.image = null;
imageLoading = false;
}
lastUpdate = lastImageUpdate = thisImageUpdate;
}
public final boolean
imageUpdate(Image image, int flags, int x, int y, int width, int height) {
boolean ret = true;
synchronized(this) {
if((flags&ALLBITS) == ALLBITS) {
ret = false;
this.image = image;
imageLoading = false;
notifyAll();
} else if((flags&(ABORT|ERROR)) != 0) {
ret = false;
imageLoading = false;
notifyAll();
}
}
return(ret);
}
////////////////////////////////////////////////////////////////////////
//
// Private methods
//
////////////////////////////////////////////////////////////////////////
private void bboxCheckSet() {
Rectangle2D oldbox = bbox;
bbox = null;
Rectangle2D newbox = null;
try {
newbox = rawBounds2D();
}
catch(Exception ex) {
throw (RuntimeException)(ex.fillInStackTrace());
}
finally {
bbox = oldbox;
}
if(newbox == null) {
if(element.isSubgraph() && ((Subgraph)element).countOfElements(SUBGRAPH|NODE|EDGE) == 0) {
newbox = new Rectangle2D.Double();
} else {
throw new InternalError(“new bounding box of \”” + element.getName() + “\” is null”);
}
}
if(
(oldbox == null && newbox != null)
||
(oldbox != null && newbox == null)
||
(newbox != null && !newbox.equals(oldbox))
) {
// bounding box has changed so null out existing bboxes of enclosing subgraphs
Subgraph prnt = element.getSubgraph();
while(prnt != null) {
if(prnt.grappaNexus != null) {
prnt.grappaNexus.bbox = null;
}
prnt = prnt.getSubgraph();
}
// commit
bbox = newbox;
lastUpdate = System.currentTimeMillis();
}
}
////////////////////////////////////////////////////////////////////////
//
// Cloneable interface
//
////////////////////////////////////////////////////////////////////////
/**
* Creates a new object of the same class as this object.
*
* @return a clone of this instance.
* @exception OutOfMemoryError if there is not enough memory.
* @see java.lang.Cloneable
*/
public Object clone() {
try {
GrappaNexus copy = (GrappaNexus) super.clone();
if(shape != null) {
if(shapeType == LINE_SHAPE) {
copy.shape = (Shape) ((GrappaLine)shape).clone();
} else if(shapeType == BOX_SHAPE) {
copy.shape = (Shape) ((Rectangle2D)shape).clone();
} else if(shapeType == ROUNDEDBOX_SHAPE) {
copy.shape = (Shape) ((RoundRectangle2D)shape).clone();
} else if(shapeType == OVAL_SHAPE) {
copy.shape = (Shape) ((Ellipse2D)shape).clone();
} else if((shapeType&GRAPPA_SHAPE) != 0) {
copy.shape = (Shape) ((GrappaShape)shape).clone();
} else {
copy.shape = (Shape) ((GeneralPath)shape).clone();
}
}
if(textArea != null) {
copy.textArea = (Area) textArea.clone();
}
return copy;
} catch (CloneNotSupportedException e) {
// this shouldn’t happen, since we are Cloneable
throw new InternalError();
}
}
////////////////////////////////////////////////////////////////////////
//
// Shape interface
//
////////////////////////////////////////////////////////////////////////
public boolean contains(double x, double y) {
boolean contains = false;
if(shape != null) {
contains = shape.contains(x, y);
}
if(
textArea != null && !contains && !clearText && drawText
&&
(
(element.isNode() && element.getGraph().getShowNodeLabels())
||
(element.isEdge() && element.getGraph().getShowEdgeLabels())
||
(element.isSubgraph() && element.getGraph().getShowSubgraphLabels())
)
) {
contains = textArea.contains(x, y);
}
return(contains);
}
public boolean contains(double x, double y, double width, double height) {
boolean contains = false;
if(shape != null) {
contains = shape.contains(x, y, width, height);
}
if(
textArea != null && !contains && !clearText && drawText
&&
(
(element.isNode() && element.getGraph().getShowNodeLabels())
||
(element.isEdge() && element.getGraph().getShowEdgeLabels())
||
(element.isSubgraph() && element.getGraph().getShowSubgraphLabels())
)
) {
contains = textArea.contains(x, y, width, height);
}
return(contains);
}
public boolean contains(Point2D p) {
return(contains(p.getX(),p.getY()));
}
public boolean contains(Rectangle2D r) {
return(contains(r.getX(), r.getY(), r.getWidth(), r.getHeight()));
}
public Rectangle getBounds() {
return(getBounds2D().getBounds());
}
public Rectangle2D getBounds2D() {
if(dirty) {
bbox = null;
updateShape();
}
if(bbox == null) {
if(shape != null) {
bbox = shape.getBounds2D();
}
if(textArea != null && Grappa.shapeBoundText && boundText) {
if(bbox == null) {
bbox = textArea.getBounds();
} else {
bbox.add(textArea.getBounds());
}
}
if(bbox.getHeight() == 0)
bbox.setRect(bbox.getX(),bbox.getY(),bbox.getWidth(),0.01);
if(bbox.getWidth() == 0)
bbox.setRect(bbox.getX(),bbox.getY(),0.01,bbox.getHeight());
}
// return a clone so no one can mess with the real values
return((Rectangle2D)(bbox.clone()));
}
// variation for use in Grappa
Rectangle2D rawBounds2D() {
if(dirty) {
bbox = null;
updateShape();
}
if(bbox == null) {
if(shape != null) {
bbox = shape.getBounds2D();
}
if(textArea != null && Grappa.shapeBoundText && boundText) {
if(bbox == null) {
bbox = textArea.getBounds();
} else {
bbox.add(textArea.getBounds());
}
}
if(bbox.getHeight() == 0)
bbox.setRect(bbox.getX(),bbox.getY(),bbox.getWidth(),0.01);
if(bbox.getWidth() == 0)
bbox.setRect(bbox.getX(),bbox.getY(),0.01,bbox.getHeight());
}
return(bbox);
}
/**
* Equivalent to getPathIterator(null).
*
* @see getPathIterator(AffineTransform)
*/
public PathIterator getPathIterator() {
return new GrappaPathIterator(this, null);
}
public PathIterator getPathIterator(AffineTransform at) {
return new GrappaPathIterator(this, at);
}
public PathIterator getPathIterator(AffineTransform at, double flatness) {
return new FlatteningPathIterator(new GrappaPathIterator(this, at), flatness);
}
public boolean intersects(double x, double y, double width, double height) {
boolean intersects = false;
if(shape != null) {
intersects = shape.intersects(x, y, width, height);
}
if(
textArea != null && !intersects && !clearText && drawText
&&
(
(element.isNode() && element.getGraph().getShowNodeLabels())
||
(element.isEdge() && element.getGraph().getShowEdgeLabels())
||
(element.isSubgraph() && element.getGraph().getShowSubgraphLabels())
)
) {
intersects = textArea.intersects(x, y, width, height);
}
return(intersects);
}
public boolean intersects(Rectangle2D r) {
return(intersects(r.getX(), r.getY(), r.getWidth(), r.getHeight()));
}
////////////////////////////////////////////////////////////////////////
//
// Observer interface
//
////////////////////////////////////////////////////////////////////////
/**
* This method is called whenever the observed object is changed.
* When certain observed attributes (attributes of interest)
* are changed, this method will update the GrappaNexus as needed.
*
* @param obs the Observable must be an Attribute
* @param arg either a Long giving the update time of the Attribute as returned by System.getTimeInMillis() or it is a two element Object array, where the first element is a new Attribute to be observed in place of that passed via obs and the second element is the update time of this new Attribute.
*/
public void update(java.util.Observable obs, Object arg) {
// begin boilerplate
if(!(obs instanceof Attribute)) {
throw new IllegalArgumentException(“expected to be observing attributes only (obs) for \”” + element.getName() + “\””);
}
Attribute attr = (Attribute)obs;
if(arg instanceof Object[]) {
Object[] args = (Object[])arg;
if(args.length == 2 && args[0] instanceof Attribute && args[1] instanceof Long) {
attr.deleteObserver(this);
attr = (Attribute)args[0];
attr.addObserver(this);
// in case we call: super.update(obs,arg)
obs = attr;
arg = args[1];
} else {
throw new IllegalArgumentException(“badly formated update information for \”” + element.getName() + “\””);
}
}
// end boilerplate
// when this object is created it should register with the
// appropriate Attributes based on how it was created;
// this method will then see what has been updated
// and set flags in this object (and put tokens in an update
// stack in Graph is autoUpdate is true) so that the appropriate
// parts will be updated before any drawing occurs.
if(arg instanceof Long) {
String attrName = attr.getName();
int attrHash = attr.getNameHash();
long thisUpdate = ((Long)arg).longValue() + 1L;
if(element == null || !element.reserve()) return;
// reset
objs = null;
switch(element.getType()) {
case NODE:
if(
(POS_HASH == attrHash && POS_ATTR.equals(attrName))
||
(WIDTH_HASH == attrHash && WIDTH_ATTR.equals(attrName))
||
(HEIGHT_HASH == attrHash && HEIGHT_ATTR.equals(attrName))
||
(SHAPE_HASH == attrHash && SHAPE_ATTR.equals(attrName))
) {
if(lastShapeUpdate < thisUpdate) {
updateShape();
if(Grappa.autoPositionNodeLabel) {
updateText();
}
}
} else if(
(LABEL_HASH == attrHash && LABEL_ATTR.equals(attrName))
||
(
!Grappa.autoPositionNodeLabel
&&
(LP_HASH == attrHash && LP_ATTR.equals(attrName)) // in case it is used
)
||
(FONTSIZE_HASH == attrHash && FONTSIZE_ATTR.equals(attrName))
||
(FONTNAME_HASH == attrHash && FONTNAME_ATTR.equals(attrName))
||
(FONTSTYLE_HASH == attrHash && FONTSTYLE_ATTR.equals(attrName))
) {
if(lastTextUpdate < thisUpdate) {
updateText();
}
} else if(
(STYLE_HASH == attrHash && STYLE_ATTR.equals(attrName))
) {
if(lastStyleUpdate < thisUpdate) {
updateStyle();
}
} else if(
(COLOR_HASH == attrHash && COLOR_ATTR.equals(attrName))
||
(FONTCOLOR_HASH == attrHash && FONTCOLOR_ATTR.equals(attrName))
) {
if(lastDecorationUpdate < thisUpdate) {
updateDecoration();
}
} else if(
(IMAGE_HASH == attrHash && IMAGE_ATTR.equals(attrName))
) {
if(lastImageUpdate < thisUpdate) {
updateImage();
}
} else {
throw new InternalError("update called for \"" + element.getName() + "\" with an unmonitored attribute: " + attrName);
}
break;
case EDGE:
if(
(POS_HASH == attrHash && POS_ATTR.equals(attrName))
) {
if(lastShapeUpdate < thisUpdate) {
updateShape();
}
} else if(
(LABEL_HASH == attrHash && LABEL_ATTR.equals(attrName))
||
(LP_HASH == attrHash && LP_ATTR.equals(attrName))
||
(HEADLABEL_HASH == attrHash && HEADLABEL_ATTR.equals(attrName))
||
(HEADLP_HASH == attrHash && HEADLP_ATTR.equals(attrName))
||
(TAILLABEL_HASH == attrHash && TAILLABEL_ATTR.equals(attrName))
||
(TAILLP_HASH == attrHash && TAILLP_ATTR.equals(attrName))
||
(FONTSIZE_HASH == attrHash && FONTSIZE_ATTR.equals(attrName))
||
(FONTNAME_HASH == attrHash && FONTNAME_ATTR.equals(attrName))
||
(FONTSTYLE_HASH == attrHash && FONTSTYLE_ATTR.equals(attrName))
) {
if(lastTextUpdate < thisUpdate) {
updateText();
}
} else if(
(STYLE_HASH == attrHash && STYLE_ATTR.equals(attrName))
) {
if(lastStyleUpdate < thisUpdate) {
updateStyle();
}
} else if(
(COLOR_HASH == attrHash && COLOR_ATTR.equals(attrName))
||
(DIR_HASH == attrHash && DIR_ATTR.equals(attrName))
||
(FONTCOLOR_HASH == attrHash && FONTCOLOR_ATTR.equals(attrName))
) {
if(lastDecorationUpdate < thisUpdate) {
updateDecoration();
}
} else if(
(IMAGE_HASH == attrHash && IMAGE_ATTR.equals(attrName))
) {
if(lastImageUpdate < thisUpdate) {
updateImage();
}
} else {
throw new InternalError("update called for \"" + element.getName() + "\" with an unmonitored attribute: " + attrName);
}
break;
case SUBGRAPH:
if(
(LABEL_HASH == attrHash && LABEL_ATTR.equals(attrName))
||
(LP_HASH == attrHash && LP_ATTR.equals(attrName))
||
(FONTSIZE_HASH == attrHash && FONTSIZE_ATTR.equals(attrName))
||
(FONTNAME_HASH == attrHash && FONTNAME_ATTR.equals(attrName))
||
(FONTSTYLE_HASH == attrHash && FONTSTYLE_ATTR.equals(attrName))
) {
if(lastTextUpdate < thisUpdate) {
updateText();
}
} else if(
(STYLE_HASH == attrHash && STYLE_ATTR.equals(attrName))
) {
if(lastStyleUpdate < thisUpdate) {
updateStyle();
}
} else if(
(COLOR_HASH == attrHash && COLOR_ATTR.equals(attrName))
||
(FONTCOLOR_HASH == attrHash && FONTCOLOR_ATTR.equals(attrName))
) {
if(lastDecorationUpdate < thisUpdate) {
updateDecoration();
}
} else if(
(IMAGE_HASH == attrHash && IMAGE_ATTR.equals(attrName))
) {
if(lastImageUpdate < thisUpdate) {
updateImage();
}
} else if(
(MINBOX_HASH == attrHash && MINBOX_ATTR.equals(attrName))
||
(MINSIZE_HASH == attrHash && MINSIZE_ATTR.equals(attrName))
) {
bbox = null;
} else {
throw new InternalError("update called for \"" + element.getName() + "\" with an unmonitored attribute: " + attrName);
}
break;
}
element.release();
} else {
throw new InternalError("update called for shape of element \"" + element.getName() + "\" without proper format");
}
}
/**
* Draw the element using the supplied Graphics2D context.
*
* @param g2d the Graphics2D context to be used for drawing
*/
void draw(java.awt.Graphics2D g2d) {
if(shape instanceof CustomRenderer)
((CustomRenderer)shape).draw(g2d);
else
g2d.draw(this);
}
/**
* Fill the element using the supplied Graphics2D context.
*
* @param g2d the Graphics2D context to be used for drawing
*/
void fill(java.awt.Graphics2D g2d) {
if(shape instanceof CustomRenderer)
((CustomRenderer)shape).fill(g2d);
else
g2d.fill(this);
}
/**
* Draw the image associated with the IMAGE_ATTR
* using the supplied Graphics2D context.
*
* @param g2d the Graphics2D context to be used for drawing
*/
void drawImage(java.awt.Graphics2D g2d) {
if(Grappa.waitForImages && imageLoading) {
synchronized(this) {
try {
wait();
}
catch(InterruptedException e) {}
}
}
if(image != null) {
if(shape instanceof CustomRenderer) {
((CustomRenderer)shape).drawImage(g2d);
} else {
Rectangle sbox = shape.getBounds();
Shape clip = g2d.getClip();
g2d.clip(shape);
g2d.drawImage(image, sbox.x, sbox.y, sbox.width, sbox.height, null);
g2d.setClip(clip);
}
}
}
}
att/grappa/GrappaPanel.java
att/grappa/GrappaPanel.java/*
* This software may only be used by you under license from AT&T Corp.
* ("AT&T"). A copy of AT&T's Source Code Agreement is available at
* AT&T's Internet website having the URL:
*
* If you received this software without first entering into a license
* with AT&T, you have an infringing copy of this software and cannot use
* it without violating AT&T’s intellectual property rights.
*/
package att.grappa;
import java.awt.*;
import java.awt.geom.*;
import java.awt.print.*;
import java.util.Enumeration;
import java.util.Vector;
import javax.swing.event.AncestorListener;
import javax.swing.event.AncestorEvent;
import javax.swing.event.PopupMenuListener;
import javax.swing.event.PopupMenuEvent;
import javax.swing.Scrollable;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import java.awt.event.MouseEvent;
import java.awt.event.ComponentListener;
import java.awt.event.ComponentEvent;
/**
* A class used for drawing the graph.
*
* @version 1.2, 26 May 2005; Copyright 1996 – 2005 by AT&T Corp.
* @author John Mocenigo, Research @ AT&T Labs
*/
public class GrappaPanel extends javax.swing.JPanel
implements
att.grappa.GrappaConstants,
ComponentListener,
AncestorListener, PopupMenuListener,
MouseListener, MouseMotionListener,
Printable,
Runnable,
Scrollable
{
Graph graph;
Subgraph subgraph;
GrappaBacker backer;
boolean nodeLabels, edgeLabels, subgLabels;
AffineTransform transform = null;
AffineTransform oldTransform = null;
AffineTransform inverseTransform = null;
Vector elementVector = null;
int nextElement = -1;
boolean scaleToFit = false;
GrappaSize scaleToSize = null;
GrappaListener grappaListener = null;
private Element pressedElement = null;
private GrappaPoint pressedPoint = null;
private int pressedModifiers = 0;
private GrappaStyle selectionStyle = null;
private GrappaStyle deletionStyle = null;
private double scaleFactor = 1;
private double scaleInfo = 1;
private GrappaBox outline = null;
private GrappaBox savedOutline = null;
private GrappaBox zoomBox = null;
private boolean inMenu = false;
private boolean scaleChanged = false;
private boolean paintActive = false;
private Point2D panelcpt = null;
/**
* Constructs a new canvas associated with a particular subgraph.
* Keep in mind that Graph is a sub-class of Subgraph so that
* usually a Graph object is passed to the constructor.
*
* @param subgraph the subgraph to be rendered on the canvas
*/
public GrappaPanel(Subgraph subgraph) {
this(subgraph, null);
}
/**
* Constructs a new canvas associated with a particular subgraph.
*
* @param subgraph the subgraph to be rendered on the canvas.
* @param backer used to draw a background for the graph.
*/
public GrappaPanel(Subgraph subgraph, GrappaBacker backer) {
super();
this.subgraph = subgraph;
this.backer = backer;
this.graph = subgraph.getGraph();
addAncestorListener(this);
addComponentListener(this);
selectionStyle = (GrappaStyle)(graph.getGrappaAttributeValue(GRAPPA_SELECTION_STYLE_ATTR));
deletionStyle = (GrappaStyle)(graph.getGrappaAttributeValue(GRAPPA_DELETION_STYLE_ATTR));
}
/**
* Adds the specified listener to receive mouse events from this graph.
*
* @param listener the event listener.
* @return the previous event listener.
*
* @see GrappaAdapter
*/
public GrappaListener addGrappaListener(GrappaListener listener) {
GrappaListener oldGL = grappaListener;
grappaListener = listener;
if(grappaListener == null) {
if (oldGL != null) {
removeMouseListener(this);
removeMouseMotionListener(this);
}
setToolTipText(null);
} else {
if (oldGL == null) {
addMouseListener(this);
addMouseMotionListener(this);
}
String tip = graph.getToolTipText();
if(tip == null) {
tip = Grappa.getToolTipText();
}
setToolTipText(tip);
}
return(oldGL);
}
/**
* Removes the current listener from this graph.
* Equivalent to addGrappaListener(null).
*
* @return the event listener just removed.
*/
public GrappaListener removeGrappaListener() {
return(addGrappaListener(null));
}
public int print(Graphics g, PageFormat pf, int pi)
throws PrinterException
{
GrappaSize prevToSize = scaleToSize;
boolean prevToFit = scaleToFit;
if (pi >= 1) {
return Printable.NO_SUCH_PAGE;
}
try {
scaleToFit = false;
scaleToSize = new GrappaSize(pf.getImageableWidth(), pf.getImageableHeight());
((Graphics2D)g).translate(pf.getImageableX(), pf.getImageableY());
paintComponent(g);
}
finally {
scaleToSize = prevToSize;
scaleToFit = prevToFit;
}
return Printable.PAGE_EXISTS;
}
public void paintComponent(Graphics g) {
Point2D cpt = null;
if(Grappa.synchronizePaint || graph.getSynchronizePaint()) {
if(graph.setPaint(true)) {
cpt = componentPaint(g);
graph.setPaint(false);
}
} else {
cpt = componentPaint(g);
}
if (cpt != null) {
setCPT(cpt);
EventQueue.invokeLater(this);
}
}
void setCPT(Point2D cpt) {
panelcpt = cpt;
}
Point2D getCPT() {
return(panelcpt);
}
private Point2D componentPaint(Graphics g) {
if(subgraph == null || !subgraph.reserve()) return(null);
Graphics2D g2d = (Graphics2D)g;
int i;
long thisPaint = System.currentTimeMillis();
Container prnt;
Container tprnt;
Point2D cpt = null;
//Color origBackground = g2d.getBackground();
////Composite origComposite = g2d.getComposite();
//Paint origPaint = g2d.getPaint();
//RenderingHints origRenderingHints = g2d.getRenderingHints();
//Stroke origStroke = g2d.getStroke();
//AffineTransform origAffineTransform = g2d.getTransform();
//Font origFont = g2d.getFont();
elementVector = null;
GrappaBox bbox = new GrappaBox(subgraph.getBoundingBox());
if(bbox == null) return(null);
GrappaSize margins = (GrappaSize)(subgraph.getAttributeValue(MARGIN_ATTR));
if(margins != null) {
double x_margin = PointsPerInch * margins.width;
double y_margin = PointsPerInch * margins.height;
bbox.x -= x_margin;
bbox.y -= y_margin;
bbox.width += 2.0 * x_margin;
bbox.height += 2.0 * y_margin;
}
subgLabels = subgraph.getShowSubgraphLabels();
nodeLabels = subgraph.getShowNodeLabels();
edgeLabels = subgraph.getShowEdgeLabels();
if(Grappa.useAntiAliasing) {
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,RenderingHints.VALUE_ANTIALIAS_ON);
} else {
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,RenderingHints.VALUE_ANTIALIAS_OFF);
}
if(Grappa.antiAliasText) {
g2d.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING,RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
} else {
g2d.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING,RenderingHints.VALUE_TEXT_ANTIALIAS_OFF);
}
if(Grappa.useFractionalMetrics) {
g2d.setRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS,RenderingHints.VALUE_FRACTIONALMETRICS_ON);
}
g2d.setStroke(GrappaStyle.defaultStroke);
oldTransform = transform;
transform = new AffineTransform();
if(scaleToFit || scaleToSize != null) {
scaleFactor = 1;
zoomBox = null;
double scaleToWidth = 0;
double scaleToHeight = 0;
if(scaleToFit) {
tprnt = prnt = getParent();
while (tprnt != null && !(tprnt instanceof javax.swing.JViewport))
tprnt = tprnt.getParent();
if (tprnt != null)
prnt = tprnt;
if(prnt instanceof javax.swing.JViewport) {
Dimension sz = ((javax.swing.JViewport)prnt).getSize();
scaleToWidth = sz.width;
scaleToHeight = sz.height;
} else {
Rectangle scaleTo = getVisibleRect();
scaleToWidth = scaleTo.width;
scaleToHeight = scaleTo.height;
}
} else {
scaleToWidth = scaleToSize.width;
scaleToHeight = scaleToSize.height;
}
double widthRatio = scaleToWidth / bbox.getWidth();
double heightRatio = scaleToHeight / bbox.getHeight();
double xTranslate = 0;
double yTranslate = 0;
if(widthRatio < heightRatio) {
xTranslate = (scaleToWidth - widthRatio * bbox.getWidth()) / ( 2.0 * widthRatio);
yTranslate = (scaleToHeight - widthRatio * bbox.getHeight()) / (2.0 * widthRatio);
transform.scale(widthRatio, widthRatio);
scaleInfo = widthRatio;
} else {
xTranslate = (scaleToWidth - heightRatio * bbox.getWidth()) / (2.0 * heightRatio);
yTranslate = (scaleToHeight - heightRatio * bbox.getHeight()) / (2.0 * heightRatio);
transform.scale(heightRatio, heightRatio);
scaleInfo = heightRatio;
}
transform.translate(xTranslate, yTranslate);
setSize(new Dimension((int)Math.ceil(scaleToWidth),(int)Math.ceil(scaleToHeight)));
setPreferredSize(new Dimension((int)Math.ceil(scaleToWidth),(int)Math.ceil(scaleToHeight)));
transform.translate(-bbox.getMinX(),-bbox.getMinY());
scaleFactor = scaleInfo;
} else if(zoomBox != null) {
//System.err.println("zoombox");
Rectangle r;
tprnt = prnt = getParent();
while (tprnt != null && !(tprnt instanceof javax.swing.JViewport))
tprnt = tprnt.getParent();
if (tprnt != null)
prnt = tprnt;
if(prnt instanceof javax.swing.JViewport) {
Dimension sz = ((javax.swing.JViewport)prnt).getSize();
r = new Rectangle(0,0,sz.width,sz.height);
} else
r = getVisibleRect();
scaleFactor = 1;
if(zoomBox.width != 0 && zoomBox.height != 0 && oldTransform != null) {
GrappaBox zb = new GrappaBox(oldTransform.createTransformedShape(zoomBox).getBounds2D());
double scaleToWidth = r.width;
double scaleToHeight = r.height;
//System.err.println("zb=("+zb.x+","+zb.y+","+zb.width+","+zb.height+")");
//System.err.println("zB=("+zoomBox.x+","+zoomBox.y+","+zoomBox.width+","+zoomBox.height+")");
//System.err.println("vr=("+r.x+","+r.y+","+r.width+","+r.height+")");
double widthRatio = scaleToWidth / zoomBox.width;
double heightRatio = scaleToHeight / zoomBox.height;
double xTranslate = 0;
double yTranslate = 0;
if(widthRatio < heightRatio) {
scaleFactor = widthRatio;
} else {
scaleFactor = heightRatio;
}
transform.scale(scaleFactor, scaleFactor);
scaleInfo = scaleFactor;
//transform.translate(xTranslate, yTranslate);
scaleToWidth = bbox.getWidth() * scaleFactor;
scaleToHeight = bbox.getHeight() * scaleFactor;
setSize(new Dimension((int)Math.ceil(scaleToWidth),(int)Math.ceil(scaleToHeight)));
setPreferredSize(new Dimension((int)Math.ceil(scaleToWidth),(int)Math.ceil(scaleToHeight)));
transform.translate(-bbox.getMinX(),-bbox.getMinY());
cpt = new Point2D.Double(zoomBox.getCenterX(), zoomBox.getCenterY());
}
zoomBox = null;
//System.err.println("scaleFactor="+scaleFactor);
//transform.scale(scaleFactor, scaleFactor);
//int w = (int)Math.ceil(bbox.getWidth()*scaleFactor);
//int h = (int)Math.ceil(bbox.getHeight()*scaleFactor);
//w = w < r.width ? r.width : w;
//h = h < r.height ? r.height : h;
//setSize(new Dimension(w,h));
//setPreferredSize(new Dimension(w,h));
scaleFactor = scaleInfo;
} else if(scaleFactor != 1) {
Rectangle r = getVisibleRect();
cpt = null;
prnt = null;
if(scaleChanged) {
tprnt = prnt = getParent();
while (tprnt != null && !(tprnt instanceof javax.swing.JViewport))
tprnt = tprnt.getParent();
if (tprnt != null)
prnt = tprnt;
if(prnt instanceof javax.swing.JViewport && inverseTransform != null) {
Point2D pt = new Point2D.Double(r.x,r.y);
cpt = new Point2D.Double(r.x+r.width,r.y+r.height);
inverseTransform.transform(pt,pt);
inverseTransform.transform(cpt,cpt);
cpt.setLocation(
pt.getX() + (cpt.getX() - pt.getX())/2.,
pt.getY() + (cpt.getY() - pt.getY())/2.
);
} else {
// to save checking again below
prnt = null;
}
}
transform.scale(scaleFactor, scaleFactor);
scaleInfo = scaleFactor;
int w = (int)Math.ceil(bbox.getWidth()*scaleFactor);
int h = (int)Math.ceil(bbox.getHeight()*scaleFactor);
w = w < r.width ? r.width : w;
h = h < r.height ? r.height : h;
setSize(new Dimension(w,h));
setPreferredSize(new Dimension(w,h));
transform.translate(-bbox.getMinX(),-bbox.getMinY());
} else {
cpt = null;
prnt = null;
if(scaleChanged) {
tprnt = prnt = getParent();
while (tprnt != null && !(tprnt instanceof javax.swing.JViewport))
tprnt = tprnt.getParent();
if (tprnt != null)
prnt = tprnt;
if(prnt instanceof javax.swing.JViewport && inverseTransform != null) {
Rectangle r = getVisibleRect();
Point2D pt = new Point2D.Double(r.x,r.y);
cpt = new Point2D.Double(r.x+r.width,r.y+r.height);
inverseTransform.transform(pt,pt);
inverseTransform.transform(cpt,cpt);
cpt.setLocation(
pt.getX() + (cpt.getX() - pt.getX())/2.,
pt.getY() + (cpt.getY() - pt.getY())/2.
);
} else {
// to save checking again below
prnt = null;
}
}
scaleInfo = 1;
setSize(new Dimension((int)Math.ceil(bbox.getWidth()),(int)Math.ceil(bbox.getHeight())));
setPreferredSize(new Dimension((int)Math.ceil(bbox.getWidth()),(int)Math.ceil(bbox.getHeight())));
transform.translate(-bbox.getMinX(),-bbox.getMinY());
}
scaleChanged = false;
if(scaleInfo < Grappa.nodeLabelsScaleCutoff) {
nodeLabels = false;
}
if(scaleInfo < Grappa.edgeLabelsScaleCutoff) {
edgeLabels = false;
}
if(scaleInfo < Grappa.subgLabelsScaleCutoff) {
subgLabels = false;
}
try {
inverseTransform = transform.createInverse();
} catch(NoninvertibleTransformException nite) {
inverseTransform = null;
}
g2d.transform(transform);
Rectangle clip = g2d.getClipBounds();
// grow bounds to account for Java's frugal definition of what
// constitutes the intersectable area of a shape
clip.x--;
clip.y--;
clip.width+=2;
clip.height+=2;
synchronized(graph) {
GrappaNexus grappaNexus = subgraph.grappaNexus;
if(grappaNexus != null) {
Color bkgdColor = null;
// do fill now in case there is a Backer supplied
g2d.setPaint(bkgdColor = (Color)(graph.getGrappaAttributeValue(GRAPPA_BACKGROUND_COLOR_ATTR)));
g2d.fill(clip);
if(grappaNexus.style.filled || grappaNexus.image != null) {
if(grappaNexus.style.filled) {
if (grappaNexus.fillcolor != null) {
g2d.setPaint(bkgdColor = grappaNexus.fillcolor);
grappaNexus.fill(g2d);
if (grappaNexus.color != null)
g2d.setPaint(grappaNexus.color);
else
g2d.setPaint(grappaNexus.style.line_color);
} else {
g2d.setPaint(bkgdColor = grappaNexus.color);
grappaNexus.fill(g2d);
g2d.setPaint(grappaNexus.style.line_color);
}
}
grappaNexus.drawImage(g2d);
// for the main graph, only outline when filling/imaging
if(GrappaStyle.defaultStroke != grappaNexus.style.stroke) {
g2d.setStroke(grappaNexus.style.stroke);
grappaNexus.draw(g2d);
g2d.setStroke(GrappaStyle.defaultStroke);
} else {
grappaNexus.draw(g2d);
}
}
if(backer != null && Grappa.backgroundDrawing) {
backer.drawBackground(g2d, graph, bbox, clip);
}
paintSubgraph(g2d, subgraph, clip, bkgdColor);
}
}
//g2d.setBackground(origBackground);
////g2d.setComposite(origComposite);
//g2d.setPaint(origPaint);
//g2d.setRenderingHints(origRenderingHints);
//g2d.setStroke(origStroke);
//g2d.setTransform(origAffineTransform);
//g2d.setFont(origFont);
subgraph.release();
return(cpt);
}
/**
* Centers the panel at the supplied point.
*
* @param cpt requested center point
*
*/
public void centerPanelAtPoint(Point2D cpt) {
Container prnt, tprnt;
javax.swing.JViewport viewport;
//System.err.println("cpt="+cpt);
tprnt = prnt = getParent();
while (tprnt != null && !(tprnt instanceof javax.swing.JViewport))
tprnt = tprnt.getParent();
if (tprnt != null)
prnt = tprnt;
if (prnt instanceof javax.swing.JViewport) {
viewport = (javax.swing.JViewport)prnt;
transform.transform(cpt,cpt);
Dimension viewsize = viewport.getExtentSize();
viewport.setViewPosition(new Point((int)(cpt.getX() - ((double)viewsize.width)/2.), (int)(cpt.getY() - ((double)viewsize.height)/2.)));
} // else ...
}
/**
* Get the AffineTransform that applies to this drawing.
*
* @return the AffineTransform that applies to this drawing.
*/
public AffineTransform getTransform() {
return (AffineTransform)(transform.clone());
}
/**
* Get the inverse AffineTransform that applies to this drawing.
*
* @return the inverse AffineTransform that applies to this drawing.
*/
public AffineTransform getInverseTransform() {
return inverseTransform;
}
/**
* Registers the default text to display in a tool tip.
* Setting the default text to null turns off tool tips.
* The default text is displayed when the mouse is outside the
* graph boundaries, but within the panel.
*
* @see Graph#setToolTipText(String)
*/
public void setToolTipText(String tip) {
//System.err.println("tip set to: " + tip);
super.setToolTipText(tip);
}
/**
* Generate an appropriate tooltip based on the mouse location
* provided by the given event.
* @return if a GrappaListener is available, the result of its
* grappaTip() method is returned, otherwise null.
*
* @see GrappaPanel#setToolTipText(String)
*/
public String getToolTipText(MouseEvent mev) {
if(inverseTransform == null || grappaListener == null) return(null);
//System.err.println(“tip requested”);
Point2D pt = inverseTransform.transform(mev.getPoint(),null);
return(grappaListener.grappaTip(subgraph, findContainingElement(subgraph,pt), new GrappaPoint(pt.getX(), pt.getY()), mev.getModifiers(), this));
}
/**
* Enable/disable scale-to-fit mode.
*
* @param setting if true, the graph drawing is scaled to fit the panel, otherwise the graph is drawn full-size.
*/
public void setScaleToFit(boolean setting) {
scaleToFit = setting;
}
/**
* Scale the graph drawing to a specific size.
*/
public void setScaleToSize(Dimension2D scaleSize) {
if(scaleSize == null) {
scaleToSize = null;
} else {
scaleToSize = new GrappaSize(scaleSize.getWidth(), scaleSize.getHeight());
}
}
/**
* Get the subgraph being drawn on this panel.
*
* @return the subgraph being drawn on this panel.
*/
public Subgraph getSubgraph() {
return(subgraph);
}
/**
* Reset the scale factor to one.
*/
public void resetZoom() {
scaleChanged = scaleFactor != 1;
scaleFactor = 1;
zoomBox = null;
}
/**
* Check if a swept outline is still available.
*
* @return true if there is an outline available.
*/
public boolean hasOutline() {
return(savedOutline != null);
}
/**
* Clear swept outline, if any.
*/
public void clearOutline() {
savedOutline = null;
}
/**
* Zoom the drawing to the outline just swept with the mouse, if any.
*
* @return the box corresponding to the swept outline, or null.
*/
public GrappaBox zoomToOutline() {
zoomBox = null;
if(savedOutline != null) {
scaleFactor = 1;
zoomBox = new GrappaBox(savedOutline);
savedOutline = null;
}
//System.err.println(“zoomBox=” + zoomBox);
return(zoomBox);
}
/**
* Zoom the drawing to the outline just swept with the mouse, if any.
*
* @param outline the zoom bounds
* @return the box corresponding to the swept outline, or null.
*/
public GrappaBox zoomToOutline(GrappaBox outline) {
zoomBox = null;
if(outline != null) {
scaleFactor = 1;
zoomBox = new GrappaBox(outline);
}
return(zoomBox);
}
/**
* Adjust the scale factor by the supplied multiplier.
*
* @param multiplier multiply the scale factor by this amount.
* @return the value of the previous scale factor.
*/
public double multiplyScaleFactor(double multiplier) {
double old = scaleFactor;
zoomBox = null;
scaleFactor *= multiplier;
if(scaleFactor == 0) scaleFactor = old;
scaleChanged = scaleFactor != old;
return(old);
}
////////////////////////////////////////////////////////////////////////
//
// Private methods
//
////////////////////////////////////////////////////////////////////////
private void paintSubgraph(Graphics2D g2d, Subgraph subg, Shape clipper, Color bkgdColor) {
if(subg != subgraph && !subg.reserve()) return;
Rectangle2D bbox = subg.getBoundingBox();
GrappaNexus grappaNexus = subg.grappaNexus;
if(bbox != null && grappaNexus != null && subg.visible && !grappaNexus.style.invis && clipper.intersects(bbox)) {
Enumeration enm = null;
int i;
if(subg != subgraph) {
g2d.setPaint(grappaNexus.color);
if(grappaNexus.style.filled) {
if (grappaNexus.fillcolor != null) {
bkgdColor = grappaNexus.fillcolor;
grappaNexus.fill(g2d);
if (grappaNexus.color != null)
g2d.setPaint(grappaNexus.color);
else
g2d.setPaint(grappaNexus.style.line_color);
} else {
bkgdColor = grappaNexus.color;
grappaNexus.fill(g2d);
g2d.setPaint(grappaNexus.style.line_color);
}
} else if(grappaNexus.color == bkgdColor) { // using == is OK (caching)
g2d.setPaint(grappaNexus.style.line_color);
}
grappaNexus.drawImage(g2d);
if(subg.isCluster() || Grappa.outlineSubgraphs) {
if(GrappaStyle.defaultStroke != grappaNexus.style.stroke) {
g2d.setStroke(grappaNexus.style.stroke);
grappaNexus.draw(g2d);
g2d.setStroke(GrappaStyle.defaultStroke);
} else {
grappaNexus.draw(g2d);
}
}
}
if((subg.highlight&DELETION_MASK) == DELETION_MASK) {
g2d.setPaint(deletionStyle.line_color);
if(GrappaStyle.defaultStroke != deletionStyle.stroke) {
g2d.setStroke(deletionStyle.stroke);
grappaNexus.draw(g2d);
g2d.setStroke(GrappaStyle.defaultStroke);
} else {
grappaNexus.draw(g2d);
}
} else if((subg.highlight&SELECTION_MASK) == SELECTION_MASK) {
g2d.setPaint(selectionStyle.line_color);
if(GrappaStyle.defaultStroke != selectionStyle.stroke) {
g2d.setStroke(selectionStyle.stroke);
grappaNexus.draw(g2d);
g2d.setStroke(GrappaStyle.defaultStroke);
} else {
grappaNexus.draw(g2d);
}
}
if(grappaNexus.lstr != null && subgLabels) {
g2d.setFont(grappaNexus.font);
g2d.setPaint(grappaNexus.font_color);
for(i = 0; i < grappaNexus.lstr.length; i++) {
g2d.drawString(grappaNexus.lstr[i],(int)grappaNexus.lpos[i].x,(int)grappaNexus.lpos[i].y);
}
}
enm = subg.subgraphElements();
Subgraph subsubg = null;
while(enm.hasMoreElements()) {
subsubg = (Subgraph)(enm.nextElement());
if(subsubg != null) paintSubgraph(g2d, subsubg, clipper, bkgdColor);
}
Node node;
enm = subg.nodeElements();
while(enm.hasMoreElements()) {
node = (Node)(enm.nextElement());
if(node == null || !node.reserve()) continue;
if((grappaNexus = node.grappaNexus) != null && node.visible && !grappaNexus.style.invis && clipper.intersects(grappaNexus.rawBounds2D())) {
if(grappaNexus.style.filled) {
if (grappaNexus.fillcolor != null) {
g2d.setPaint(grappaNexus.fillcolor);
grappaNexus.fill(g2d);
if (grappaNexus.color != null)
g2d.setPaint(grappaNexus.color);
else
g2d.setPaint(grappaNexus.style.line_color);
} else {
g2d.setPaint(grappaNexus.color);
grappaNexus.fill(g2d);
g2d.setPaint(grappaNexus.style.line_color);
}
} else {
g2d.setPaint(grappaNexus.color);
}
grappaNexus.drawImage(g2d);
if((node.highlight&DELETION_MASK) == DELETION_MASK) {
g2d.setPaint(deletionStyle.line_color);
if(GrappaStyle.defaultStroke != deletionStyle.stroke) {
g2d.setStroke(deletionStyle.stroke);
grappaNexus.draw(g2d);
g2d.setStroke(GrappaStyle.defaultStroke);
} else {
grappaNexus.draw(g2d);
}
} else if((node.highlight&SELECTION_MASK) == SELECTION_MASK) {
g2d.setPaint(selectionStyle.line_color);
if(GrappaStyle.defaultStroke != selectionStyle.stroke) {
g2d.setStroke(selectionStyle.stroke);
grappaNexus.draw(g2d);
g2d.setStroke(GrappaStyle.defaultStroke);
} else {
grappaNexus.draw(g2d);
}
} else {
if(GrappaStyle.defaultStroke != grappaNexus.style.stroke) {
g2d.setStroke(grappaNexus.style.stroke);
grappaNexus.draw(g2d);
g2d.setStroke(GrappaStyle.defaultStroke);
} else {
grappaNexus.draw(g2d);
}
}
if(grappaNexus.lstr != null && nodeLabels) {
g2d.setFont(grappaNexus.font);
g2d.setPaint(grappaNexus.font_color);
for(i = 0; i < grappaNexus.lstr.length; i++) {
g2d.drawString(grappaNexus.lstr[i],(int)grappaNexus.lpos[i].x,(int)grappaNexus.lpos[i].y);
}
}
}
node.release();
}
Edge edge;
enm = subg.edgeElements();
while(enm.hasMoreElements()) {
edge = (Edge)(enm.nextElement());
if(edge == null || !edge.reserve()) continue;
if((grappaNexus = edge.grappaNexus) != null && edge.visible && !grappaNexus.style.invis && clipper.intersects(grappaNexus.rawBounds2D())) {
grappaNexus.drawImage(g2d);
if((edge.highlight&DELETION_MASK) == DELETION_MASK) {
g2d.setPaint(deletionStyle.line_color);
grappaNexus.fill(g2d);
if(GrappaStyle.defaultStroke != deletionStyle.stroke) {
g2d.setStroke(deletionStyle.stroke);
grappaNexus.draw(g2d);
g2d.setStroke(GrappaStyle.defaultStroke);
} else {
grappaNexus.draw(g2d);
}
} else if((edge.highlight&SELECTION_MASK) == SELECTION_MASK) {
g2d.setPaint(selectionStyle.line_color);
grappaNexus.fill(g2d);
if(GrappaStyle.defaultStroke != selectionStyle.stroke) {
g2d.setStroke(selectionStyle.stroke);
grappaNexus.draw(g2d);
g2d.setStroke(GrappaStyle.defaultStroke);
} else {
grappaNexus.draw(g2d);
}
} else {
g2d.setPaint(grappaNexus.color);
grappaNexus.fill(g2d);
if(GrappaStyle.defaultStroke != grappaNexus.style.stroke) {
g2d.setStroke(grappaNexus.style.stroke);
grappaNexus.draw(g2d);
g2d.setStroke(GrappaStyle.defaultStroke);
} else {
grappaNexus.draw(g2d);
}
}
if(grappaNexus.lstr != null && edgeLabels) {
g2d.setFont(grappaNexus.font);
g2d.setPaint(grappaNexus.font_color);
for(i = 0; i < grappaNexus.lstr.length; i++) {
g2d.drawString(grappaNexus.lstr[i],(int)grappaNexus.lpos[i].x,(int)grappaNexus.lpos[i].y);
}
}
}
edge.release();
}
}
subg.release();
}
private Element findContainingElement(Subgraph subg, Point2D pt) {
return(findContainingElement(subg, pt, null));
}
private Element findContainingElement(Subgraph subg, Point2D pt, Element crnt) {
Element elem;
Element[] stash = new Element[2];
stash[0] = crnt;
stash[1] = null;
if((elem = reallyFindContainingElement(subg, pt, stash)) == null)
elem = stash[1];
return(elem);
}
private Element reallyFindContainingElement(Subgraph subg, Point2D pt, Element[] stash) {
Enumeration enm;
Rectangle2D bb = subg.getBoundingBox();
GrappaNexus grappaNexus = null;
if(bb.contains(pt)) {
if((Grappa.elementSelection&EDGE) == EDGE) {
enm = subg.edgeElements();
Edge edge;
while(enm.hasMoreElements()) {
edge = (Edge)enm.nextElement();
if((grappaNexus = edge.grappaNexus) == null || !edge.selectable) continue;
if(grappaNexus.rawBounds2D().contains(pt)) {
if(grappaNexus.contains(pt.getX(),pt.getY())) {
if(stash[0] == null)
return((Element)edge);
if(stash[1] == null)
stash[1] = edge;
if(stash[0] == edge)
stash[0] = null;
}
}
}
}
if((Grappa.elementSelection&NODE) == NODE) {
enm = subg.nodeElements();
Node node;
while(enm.hasMoreElements()) {
node = (Node)enm.nextElement();
if((grappaNexus = node.grappaNexus) == null || !node.selectable) continue;
if(grappaNexus.rawBounds2D().contains(pt)) {
if(grappaNexus.contains(pt)) {
if(stash[0] == null)
return((Element)node);
if(stash[1] == null)
stash[1] = node;
if(stash[0] == node)
stash[0] = null;
}
}
}
}
Element subelem = null;
enm = subg.subgraphElements();
while(enm.hasMoreElements()) {
if((subelem = reallyFindContainingElement((Subgraph)(enm.nextElement()), pt, stash)) != null && subelem.selectable) {
if(stash[0] == null)
return(subelem);
if(stash[1] == null)
stash[1] = subelem;
if(stash[0] == subelem)
stash[0] = null;
}
}
if((Grappa.elementSelection&SUBGRAPH) == SUBGRAPH && subg.selectable) {
if(stash[0] == null)
return((Element)subg);
if(stash[1] == null)
stash[1] = subg;
if(stash[0] == subg)
stash[0] = null;
}
}
return(null);
}
///////////////////////////////////////////////////////////////////
//
// AncestorListener Interface
//
///////////////////////////////////////////////////////////////////
public void ancestorMoved(AncestorEvent aev) {
// don't care
}
public void ancestorAdded(AncestorEvent aev) {
graph.addPanel(this);
}
public void ancestorRemoved(AncestorEvent aev) {
graph.removePanel(this);
}
///////////////////////////////////////////////////////////////////
//
// ComponentListener Interface
//
///////////////////////////////////////////////////////////////////
public void componentHidden(ComponentEvent cev) {
// don't care
}
public void componentMoved(ComponentEvent cev) {
// don't care
}
public void componentResized(ComponentEvent cev) {
// Needed to reset JScrollPane scrollbars, for example
revalidate();
}
public void componentShown(ComponentEvent cev) {
// don't care
}
///////////////////////////////////////////////////////////////////
//
// PopupMenuListener Interface
//
///////////////////////////////////////////////////////////////////
public void popupMenuCanceled(PopupMenuEvent pmev) {
// don't care
}
public void popupMenuWillBecomeInvisible(PopupMenuEvent pmev) {
inMenu = false;
}
public void popupMenuWillBecomeVisible(PopupMenuEvent pmev) {
inMenu = true;
}
///////////////////////////////////////////////////////////////////
//
// MouseListener Interface
//
///////////////////////////////////////////////////////////////////
public void mouseClicked(MouseEvent mev) {
if(inverseTransform == null || grappaListener == null || inMenu) return;
Point2D pt = inverseTransform.transform(mev.getPoint(),null);
grappaListener.grappaClicked(subgraph, findContainingElement(subgraph,pt, (subgraph.currentSelection != null && subgraph.currentSelection instanceof Element ? ((Element)subgraph.currentSelection) : null)), new GrappaPoint(pt.getX(), pt.getY()), mev.getModifiers(), mev.getClickCount(), this);
}
public void mousePressed(MouseEvent mev) {
if(inverseTransform == null || grappaListener == null || inMenu) return;
Point2D pt = inverseTransform.transform(mev.getPoint(),null);
outline = null;
grappaListener.grappaPressed(subgraph, (pressedElement = findContainingElement(subgraph,pt)), (pressedPoint = new GrappaPoint(pt.getX(), pt.getY())), (pressedModifiers = mev.getModifiers()), this);
}
public void mouseReleased(MouseEvent mev) {
if(inverseTransform == null || grappaListener == null || inMenu) return;
int modifiers = mev.getModifiers();
Point2D pt = inverseTransform.transform(mev.getPoint(),null);
GrappaPoint gpt = new GrappaPoint(pt.getX(), pt.getY());
grappaListener.grappaReleased(subgraph, findContainingElement(subgraph,pt), gpt, modifiers, pressedElement, pressedPoint, pressedModifiers, outline, this);
if((modifiers&java.awt.event.InputEvent.BUTTON1_MASK) != 0 && (modifiers&java.awt.event.InputEvent.BUTTON1_MASK) == modifiers) {
if(outline != null) {
//System.err.println("saving outline");
savedOutline = GrappaSupport.boxFromCorners(outline, pressedPoint.x, pressedPoint.y, gpt.x, gpt.y);
outline = null;
} else {
//System.err.println("clearing outline");
savedOutline = null;
}
}
}
public void mouseEntered(MouseEvent mev) {
// don't care
}
public void mouseExited(MouseEvent mev) {
// don't care
}
///////////////////////////////////////////////////////////////////
//
// MouseMotionListener Interface
//
///////////////////////////////////////////////////////////////////
public void mouseDragged(MouseEvent mev) {
if(inverseTransform == null || grappaListener == null || inMenu) return;
int modifiers = mev.getModifiers();
Point2D pt = inverseTransform.transform(mev.getPoint(),null);
GrappaPoint gpt = new GrappaPoint(pt.getX(), pt.getY());
grappaListener.grappaDragged(subgraph, gpt, modifiers, pressedElement, pressedPoint, pressedModifiers, outline, this);
if((modifiers&java.awt.event.InputEvent.BUTTON1_MASK) != 0 && (modifiers&java.awt.event.InputEvent.BUTTON1_MASK) == modifiers) {
outline = GrappaSupport.boxFromCorners(outline, pressedPoint.x, pressedPoint.y, gpt.x, gpt.y);
}
}
public void mouseMoved(MouseEvent mev) {
// don't care
}
// --- Scrollable interface ----------------------------------------
/**
* Returns the size of the bounding box of the graph augmented by
* the margin attribute and any scaling.
*
* @return The preferredSize of a JViewport whose view is this Scrollable.
* @see JViewport#getPreferredSize
*/
public Dimension getPreferredScrollableViewportSize() {
// preferred size is set above as needed, so just return it
return getPreferredSize();
}
/**
* Always returns 1 since a GrappaPanel has not logical rows or
* columns.
* @param visibleRect The view area visible within the viewport
* @param orientation Either SwingConstants.VERTICAL or SwingConstants.HORIZONTAL.
* @param direction Less than zero to scroll up/left, greater than zero for down/right.
* @return The "unit" increment for scrolling in the specified direction, which in the case of a GrappaPanel is always 1.
* @see JScrollBar#setUnitIncrement
*/
public int getScrollableUnitIncrement(Rectangle visibleRect, int orientation, int direction) {
return(1);
}
/**
* Returns 90% of the view area dimension that is in the orientation
* of the requested scroll.
* @param visibleRect The view area visible within the viewport
* @param orientation Either SwingConstants.VERTICAL or SwingConstants.HORIZONTAL.
* @param direction Less than zero to scroll up/left, greater than zero for down/right.
* @return The "unit" increment for scrolling in the specified direction, which in the case of a GrappaPanel is 90% of the visible width for a horizontal increment or 90% of the visible height for a vertical increment.
* @see JScrollBar#setBlockIncrement
*/
public int getScrollableBlockIncrement(Rectangle visibleRect, int orientation, int direction) {
int block;
if(orientation == javax.swing.SwingConstants.VERTICAL) {
block = (int)(visibleRect.height * 0.9);
} else {
block = (int)(visibleRect.width * 0.9);
}
if(block < 1)
block = 1;
return(block);
}
/**
* Always returns false as the viewport should not force the width of this
* GrappaPanel to match the width of the viewport.
*
* @return false
*/
public boolean getScrollableTracksViewportWidth() {
return( false );
}
/**
* Always returns false as the viewport should not force the height of
* this GrappaPanel to match the width of the viewport.
*
* @return false
*/
public boolean getScrollableTracksViewportHeight() {
return( false );
}
public void run() {
Point2D cpt = getCPT();
if (cpt != null) {
centerPanelAtPoint(cpt);
}
}
}
att/grappa/GrappaPathIterator.java
att/grappa/GrappaPathIterator.java/*
* This software may only be used by you under license from AT&T Corp.
* ("AT&T"). A copy of AT&T's Source Code Agreement is available at
* AT&T's Internet website having the URL:
*
* If you received this software without first entering into a license
* with AT&T, you have an infringing copy of this software and cannot use
* it without violating AT&T’s intellectual property rights.
*/
package att.grappa;
import java.awt.*;
import java.awt.geom.*;
/**
* This class provides a PathIterator for GrappaNexus shapes.
*
* @version 1.2, 26 May 2005; Copyright 1996 – 2005 by AT&T Corp.
* @author John Mocenigo, Research @ AT&T Labs
*/
public class GrappaPathIterator implements PathIterator
{
GrappaNexus grappaNexus;
AffineTransform affine;
PathIterator shapeIterator = null;
PathIterator areaIterator = null;
double[] pts = new double[6];
int type;
////////////////////////////////////////////////////////////////////////
//
// Constructors
//
////////////////////////////////////////////////////////////////////////
/**
* Constructs a new GrappaPathIterator
given a GrappaNexus.
*/
public GrappaPathIterator(GrappaNexus shape) {
this(shape, null);
}
/**
* Constructs a new GrappaPathIterator
given a GrappaNexus
* and an optional AffineTransform.
*/
public GrappaPathIterator(GrappaNexus shape, AffineTransform at) {
if(shape == null) {
throw new IllegalArgumentException(“shape cannot be null”);
}
this.grappaNexus = shape;
this.affine = at;
if(shape.shape != null) {
shapeIterator = shape.shape.getPathIterator(this.affine);
if(shapeIterator.isDone()) {
shapeIterator = null;
}
}
if(shape.textArea != null && (Grappa.shapeClearText || shape.clearText)) {
areaIterator = shape.textArea.getPathIterator(this.affine);
if(areaIterator.isDone()) {
areaIterator = null;
}
}
if(shapeIterator != null) {
type = shapeIterator.currentSegment(pts);
} else if(areaIterator != null) {
type = areaIterator.currentSegment(pts);
} else {
throw new RuntimeException(“cannot initialize; nothing to iterate over”);
}
}
////////////////////////////////////////////////////////////////////////
//
// PathIterator interface
//
////////////////////////////////////////////////////////////////////////
public int currentSegment(double[] coords) {
System.arraycopy(pts, 0, coords, 0, 6);
return(type);
}
public int currentSegment(float[] coords) {
coords[0] = (float)pts[0];
coords[1] = (float)pts[1];
coords[2] = (float)pts[2];
coords[3] = (float)pts[3];
coords[4] = (float)pts[4];
coords[5] = (float)pts[5];
return(type);
}
/**
* Return the winding rule for determining the interior of the path.
*/
public int getWindingRule() {
return(grappaNexus.getWindingRule());
}
public boolean isDone() {
return(
(shapeIterator == null || shapeIterator.isDone())
&&
(areaIterator == null || areaIterator.isDone())
);
}
public void next() {
if(shapeIterator != null) {
if(shapeIterator.isDone()) {
shapeIterator = null;
} else {
shapeIterator.next();
if(shapeIterator.isDone()) {
shapeIterator = null;
} else {
type = shapeIterator.currentSegment(pts);
}
return;
}
}
if(areaIterator != null) {
if(areaIterator.isDone()) {
areaIterator = null;
} else {
areaIterator.next();
if(areaIterator.isDone()) {
areaIterator = null;
} else {
type = areaIterator.currentSegment(pts);
}
return;
}
}
}
}
att/grappa/GrappaPoint.java
att/grappa/GrappaPoint.java/*
* This software may only be used by you under license from AT&T Corp.
* (“AT&T”). A copy of AT&T’s Source Code Agreement is available at
* AT&T’s Internet website having the URL:
*
* If you received this software without first entering into a license
* with AT&T, you have an infringing copy of this software and cannot use
* it without violating AT&T’s intellectual property rights.
*/
package att.grappa;
/**
* This class extends java.awt.geom.Point2D.Double and provides built-in
* string-to-Point2D and Point2D-to-string conversions suitable for Grappa.
*
* @version 1.2, 26 May 2005; Copyright 1996 – 2005 by AT&T Corp.
* @author John Mocenigo, Research @ AT&T Labs
*/
public class GrappaPoint extends java.awt.geom.Point2D.Double
{
/**
* Constructs and initializes a GrappaPoint
with
* coordinates (0, 0).
*/
public GrappaPoint() {
}
/**
* Constructs and initializes a GrappaPoint
with the
* specified coordinates.
* @param x, y the coordinates to which to set the newly
* constructed GrappaPoint
*/
public GrappaPoint(double x, double y) {
this.x = x;
this.y = y;
}
/**
* Constructs and initializes a GrappaPoint
with the
* coordinates derived from the specified String representation.
* The String format should be: “x-coord,y-coord”
* @param coordString String representing the coordinates to which to
* set the newly constructed GrappaPoint
*/
public GrappaPoint(String coordString) {
double[] coords = null;
try {
coords = GrappaSupport.arrayForTuple(coordString);
}
catch(NumberFormatException nfe) {
throw new IllegalArgumentException(“coordinate string (” + coordString + “) has a bad number format (” + nfe.getMessage() + “)”);
}
if(coords == null || coords.length != 2) {
throw new IllegalArgumentException(“coordinate string (” + coordString + “) does not contain 2 valid coordinates”);
}
this.x = coords[0];
this.y = (Grappa.negateStringYCoord?-coords[1]:coords[1]);
}
/**
* Provides a string representation of this object consistent
* with Grappa attributes.
*
* @return attribute-suitable string representation of this GrappaPoint.
*/
public String toAttributeString() {
return(toFormattedString(“%p”));
}
/**
* Provides a formatted string representation of this object.
*
* @param format the format used to build the string (%p is the base directive for a GrappaPoint).
* @return a string representation of this GrappaPoint.
*/
public String toFormattedString(String format) {
return(GrappaSupportPrintf.sprintf(new Object[] { format, this }));
}
/**
* Provides a generic string representation of this object.
*
* @return a generic string representation of this GrappaPoint.
*/
public String toString() {
return(x+”,”+y);
}
}
att/grappa/GrappaShape.java
att/grappa/GrappaShape.java/*
* This software may only be used by you under license from AT&T Corp.
* (“AT&T”). A copy of AT&T’s Source Code Agreement is available at
* AT&T’s Internet website having the URL:
*
* If you received this software without first entering into a license
* with AT&T, you have an infringing copy of this software and cannot use
* it without violating AT&T’s intellectual property rights.
*/
package att.grappa;
import java.awt.*;
import java.awt.geom.*;
/**
* This class provides a flexible, parameterized polygonal shape builder.
* The guts of a GrappaShape is a GeneralPath object.
*
* @version 1.2, 26 May 2005; Copyright 1996 – 2005 by AT&T Corp.
* @author John Mocenigo, Research @ AT&T Labs
*/
public class GrappaShape
implements
GrappaConstants,
Cloneable, Shape
{
/**
* path that defines shape
*/
protected GeneralPath path = null;
private final static double RBCONST = 12.0;
private final static double RBCURVE = 0.5;
private final static double CIRCLE_XDIAG = Math.sqrt(7.0/16.0);
private final static double CIRCLE_YDIAG = 0.75;
////////////////////////////////////////////////////////////////////////
//
// Constructors
//
////////////////////////////////////////////////////////////////////////
/**
* Constructs a new GrappaShape
object.
* The winding rule for this path is defaulted (from Grappa.windingRule).
*
* @param type the shape specifier (.e.g., EGG_SHAPE).
* @param x the x-coordinate of the polygon center point.
* @param y the y-coordinate of the polygon center point.
* @param width the overall width of the polygon bounding box.
* @param height the overall height of the polygon bounding box.
* @param sidesArg the number of sides of the polygon.
* @param peripheriesArg the number of peripheries (outlines) of the polygon.
* @param distortionArg a distortion factor applied to the polygon shape, when non-zero
* @param skewArg a skewing factor applied to the polygon shape, when non-zero
* @param orientationArg an orientation angle in radians.
* @param roundedArg a directive to round the corners.
* @param diagonalsArg a directive to draw catercorners at the vertices.
* @param extra used only with the record shape at present, it provides a string of tuples giving interior partition information.
*/
public GrappaShape(int type, double x, double y, double width, double height, int sidesArg, int peripheriesArg, double distortionArg, double skewArg, double orientationArg, boolean roundedArg, boolean diagonalsArg, Object extra) {
path = new GeneralPath(Grappa.windingRule);
// defaults
int sides = 120;
int peripheries = 1;
double distortion = 0;
double skew = 0;
double orientation = 0;
boolean rounded = false;
boolean diagonals = false;
float[] rects = null;
Point2D.Float rectsMin = null;
Point2D.Float rectsMax = null;
int i;
type &= SHAPE_MASK;
switch(type) {
case MSQUARE_SHAPE:
diagonals = true;
type = BOX_SHAPE;
// fall through to BOX_SHAPE case
case BOX_SHAPE:
sides = 4;
break;
case MDIAMOND_SHAPE:
diagonals = true;
type = DIAMOND_SHAPE;
// fall through to DIAMOND_SHAPE case
case DIAMOND_SHAPE:
sides = 4;
orientation = Math.PI / 4.0;
break;
case DOUBLECIRCLE_SHAPE:
peripheries = 2;
break;
case DOUBLEOCTAGON_SHAPE:
sides = 8;
peripheries = 2;
break;
case EGG_SHAPE:
distortion = -0.3;
break;
case HEXAGON_SHAPE:
sides = 6;
break;
case HOUSE_SHAPE:
sides = 5;
distortion = -0.64;
break;
case INVERTEDHOUSE_SHAPE:
sides = 5;
distortion = -0.64;
orientation = Math.PI;
break;
case INVERTEDTRAPEZIUM_SHAPE:
sides = 4;
distortion = -0.4;
orientation = Math.PI;
break;
case INVERTEDTRIANGLE_SHAPE:
sides = 3;
orientation = Math.PI;
break;
case MRECORD_SHAPE:
rounded = true;
type = RECORD_SHAPE;
// fall through to RECORD_SHAPE case
case RECORD_SHAPE:
sides = 4;
break;
case PARALLELOGRAM_SHAPE:
sides = 4;
skew = 0.6;
break;
case PENTAGON_SHAPE:
sides = 5;
break;
case OCTAGON_SHAPE:
sides = 8;
break;
case PLAINTEXT_SHAPE:
sides = 0;
break;
case ROUNDEDBOX_SHAPE:
sides = 4;
rounded = true;
break;
case TRAPEZIUM_SHAPE:
sides = 4;
distortion = -0.4;
break;
case TRIANGLE_SHAPE:
sides = 3;
break;
case TRIPLEOCTAGON_SHAPE:
sides = 8;
peripheries = 3;
break;
case MCIRCLE_SHAPE:
diagonals = true;
type = OVAL_SHAPE;
// fall through to OVAL_SHAPE case
case OVAL_SHAPE:
case POINT_SHAPE:
case POLYGON_SHAPE:
default:
break;
case CUSTOM_SHAPE:
sidesArg = 4;
peripheriesArg = 0;
distortionArg = 0;
skewArg = 0;
orientationArg = 0;
roundedArg = false;
diagonalsArg = false;
extra = null;
break;
}
sides = (sidesArg >= 0) ? sidesArg : sides;
peripheries = (peripheriesArg >= 0) ? peripheriesArg : peripheries;
distortion = (distortionArg != 0) ? distortionArg : distortion;
skew = (skewArg != 0) ? skewArg : skew;
orientation = (orientationArg != 0) ? orientationArg : orientation;
rounded = (roundedArg) ? roundedArg : rounded;
diagonals = (diagonalsArg) ? diagonalsArg : diagonals;
if(sides < 3) {
sides = 0;
}
if(type == OVAL_SHAPE || type == POINT_SHAPE) {
sides = 120;
} else if(type == RECORD_SHAPE) {
// basically, only rounded is an option
sides = 4;
peripheries = 1;
distortion = 0;
skew = 0;
orientation = 0;
diagonals = false;
if(extra != null && extra instanceof String) {
rects = GrappaSupport.floatArrayForTuple((String)extra);
if((rects.length % 4) == 0) {
rectsMin = new Point2D.Float();
rectsMax = new Point2D.Float();
rectsMax.x = rectsMin.x = rects[0];
if(Grappa.negateStringYCoord) {
rectsMax.y = rectsMin.y = -rects[1];
} else {
rectsMax.y = rectsMin.y = rects[1];
}
for(i = 0; i < rects.length; i += 2) {
if(Grappa.negateStringYCoord)
rects[i+1] = -rects[i+1];
if(rects[i] < rectsMin.x)
rectsMin.x = rects[i];
if(rects[i] > rectsMax.x)
rectsMax.x = rects[i];
if(rects[i+1] < rectsMin.y)
rectsMin.y = rects[i+1];
if(rects[i+1] > rectsMax.y)
rectsMax.y = rects[i+1];
}
width = rectsMax.x – rectsMin.x;
height = rectsMax.y – rectsMin.y;
x = rectsMin.x + (width / 2.0);
y = rectsMin.y + (height / 2.0);
} else {
rects = null;
}
}
}
if(peripheries < 1 || sides == 0) {
path.moveTo((float)x,(float)y);
return;
}
double dtmp, alpha, beta;
double sectorAngle = 2.0 * Math.PI / (double)sides;
double sideLength = Math.sin(sectorAngle/2.0);
double skewDist, gDist, gSkew, angle;
if(skew == 0 && distortion == 0) {
skewDist = 1;
gDist = 0;
gSkew = 0;
} else {
skewDist = Math.abs(distortion) + Math.abs(skew);
skewDist = Math.sqrt(skewDist * skewDist + 1.0);
gDist = distortion * Math.sqrt(2.0) / Math.cos(sectorAngle/2.0);
gSkew = skew / 2.0;
}
GrappaPoint Rpt = new GrappaPoint();
GrappaPoint Ppt = new GrappaPoint();
GrappaPoint Bpt = new GrappaPoint();
int verts = 0;
double sinX, cosX;
GrappaPoint[] rawVertices = new GrappaPoint[sides];
GrappaPoint[] tmpVertices = null;
if(diagonals) {
tmpVertices = new GrappaPoint[2 * sides];
} else if(rounded) {
tmpVertices = new GrappaPoint[4 * sides];
}
GrappaPoint Pt0;
GrappaPoint Pt1;
double tmp1 = 0;
double tmp2 = 0;
int tverts = 0;
double delta_w = 0, delta_h = 0;
double minX = 0, minY = 0, maxX = 0, maxY = 0;
boolean tooSmall = false;
tmp1 = (peripheries - 1) * (2 * PERIPHERY_GAP);
if((width - tmp1) <= 0 || (height - tmp2) <= 0) {
peripheries = 1;
}
for(int j = 0; j < peripheries; j++) {
if(j > 0) {
if(j == 1) {
Ppt.x = rawVertices[sides-1].x;
Ppt.y = rawVertices[sides-1].y;
Rpt.x = rawVertices[0].x;
Rpt.y = rawVertices[0].y;
beta = Math.atan2(Rpt.y-Ppt.y,Rpt.x-Ppt.x);
for(i = 0; i < sides; i++) {
Ppt.x = Rpt.x;
Ppt.y = Rpt.y;
Rpt.x = rawVertices[(i+1)%sides].x;
Rpt.y = rawVertices[(i+1)%sides].y;
alpha = beta;
beta = Math.atan2(Rpt.y-Ppt.y,Rpt.x-Ppt.x);
tmp1 = (alpha + Math.PI - beta) / 2.0;
/*
* find the distance along the bisector to the
* intersection of the next periphery
*/
dtmp = PERIPHERY_GAP / Math.sin(tmp1);
// convert this distance to x and y
tmp2 = alpha - tmp1;
sinX = Math.sin(tmp2);
cosX = Math.cos(tmp2);
sinX *= dtmp;
cosX *= dtmp;
tmp1 = Ppt.x - cosX;
tmp2 = Ppt.y - sinX;
if(i == 0) {
maxX = minX = tmp1;
maxY = minY = tmp2;
} else {
if(minX > tmp1) minX = tmp1;
if(maxX < tmp1) maxX = tmp1;
if(minY > tmp2) minY = tmp2;
if(maxY < tmp2) maxY = tmp2;
}
}
delta_w = width - (maxX - minX);
delta_h = height - (maxY - minY);
}
width -= delta_w;
height -= delta_h;
}
angle = (sectorAngle - Math.PI)/2.0;
//angle = sectorAngle/2.0;
sinX = Math.sin(angle);
cosX = Math.cos(angle);
Rpt.x = 0.5 * cosX;
Rpt.y = 0.5 * sinX;
angle += (Math.PI - sectorAngle)/2.0;
//angle = Math.PI/2.0;
Bpt.x = 0;
Bpt.y = 0;
verts = 0;
for(i = 0; i < sides; i++) {
// next regular vertex
angle += sectorAngle;
sinX = Math.sin(angle);
cosX = Math.cos(angle);
Rpt.x += sideLength*cosX;
Rpt.y += sideLength*sinX;
// distort and skew
Ppt.x = Rpt.x * (skewDist + Rpt.y * gDist) + Rpt.y * gSkew;
Ppt.y = Rpt.y;
// orient Ppt
if(orientation != 0) {
alpha = orientation + Math.atan2(Ppt.y,Ppt.x);
sinX = Math.sin(alpha);
cosX = Math.cos(alpha);
dtmp = Ppt.distance(0,0);
Ppt.x = dtmp * cosX;
Ppt.y = dtmp * sinX;
}
// scale
Ppt.x *= width;
Ppt.y *= height;
// store result
rawVertices[verts++] = (GrappaPoint)Ppt.clone();
if(Bpt.x < Math.abs(Ppt.x)) Bpt.x = Math.abs(Ppt.x);
if(Bpt.y < Math.abs(Ppt.y)) Bpt.y = Math.abs(Ppt.y);
}
Bpt.x = width / (2.0 * Bpt.x);
Bpt.y = height / (2.0 * Bpt.y);
for(i = 0; i < sides; i++) {
rawVertices[i].x *= Bpt.x;
rawVertices[i].y *= Bpt.y;
}
if((rounded || diagonals) && type != OVAL_SHAPE && type != POINT_SHAPE && j == (peripheries - 1)) {
tooSmall = false;
tverts = 0;
Pt0 = rawVertices[0];
for(i = 0; i < sides; i++) {
// already scaled
Pt0 = rawVertices[i];
if(i < sides - 1) {
Pt1 = rawVertices[i+1];
} else {
Pt1 = rawVertices[0];
}
tmp2 = Pt0.distance(Pt1);
if(tmp2 < RBCONST) {
tooSmall = true;
break;
}
tmp1 = RBCONST / tmp2;
if(!diagonals) {
tmp2 = RBCURVE * tmp1;
tmpVertices[tverts++] = new GrappaPoint(
Pt0.x + tmp2 * (Pt1.x - Pt0.x),
Pt0.y + tmp2 * (Pt1.y - Pt0.y)
);
}
tmpVertices[tverts++] = new GrappaPoint(
Pt0.x + tmp1 * (Pt1.x - Pt0.x),
Pt0.y + tmp1 * (Pt1.y - Pt0.y)
);
tmp1 = 1 - tmp1;
tmpVertices[tverts++] = new GrappaPoint(
Pt0.x + tmp1 * (Pt1.x - Pt0.x),
Pt0.y + tmp1 * (Pt1.y - Pt0.y)
);
if(!diagonals) {
tmp2 = 1 - tmp2;
tmpVertices[tverts++] = new GrappaPoint(
Pt0.x + tmp2 * (Pt1.x - Pt0.x),
Pt0.y + tmp2 * (Pt1.y - Pt0.y)
);
}
}
if(tooSmall) {
for(i = 0; i < sides; i++) {
if(i == 0) {
path.moveTo((float)(x + rawVertices[i].x), (float)(y - rawVertices[i].y));
} else {
path.lineTo((float)(x + rawVertices[i].x), (float)(y - rawVertices[i].y));
}
}
} else {
if(diagonals) {
path.moveTo((float)(x + tmpVertices[0].x), (float)(y - tmpVertices[0].y));
for(i = (2*sides)-1; i > 0; i-=2) {
path.lineTo((float)(x + tmpVertices[i].x), (float)(y – tmpVertices[i].y));
path.moveTo((float)(x + tmpVertices[i-1].x), (float)(y – tmpVertices[i-1].y));
}
for(i = 0; i < sides; i++) {
if(i == 0) {
path.moveTo((float)(x + rawVertices[i].x), (float)(y - rawVertices[i].y));
} else {
path.lineTo((float)(x + rawVertices[i].x), (float)(y - rawVertices[i].y));
}
}
} else {
path.moveTo((float)(x + tmpVertices[2].x), (float)(y - tmpVertices[2].y));
for(i = 3; i < (4*sides)-2; i+=4) {
path.curveTo(
(float)(x + tmpVertices[i].x), (float)(y - tmpVertices[i].y),
(float)(x + tmpVertices[i+1].x), (float)(y - tmpVertices[i+1].y),
(float)(x + tmpVertices[i+2].x), (float)(y - tmpVertices[i+2].y)
);
path.lineTo((float)(x + tmpVertices[i+3].x), (float)(y - tmpVertices[i+3].y));
}
i = (4 * sides) - 1;
path.curveTo(
(float)(x + tmpVertices[i].x), (float)(y - tmpVertices[i].y),
(float)(x + tmpVertices[0].x), (float)(y - tmpVertices[0].y),
(float)(x + tmpVertices[1].x), (float)(y - tmpVertices[1].y)
);
}
}
} else {
for(i = 0; i < sides; i++) {
if(i == 0) {
path.moveTo((float)(x + rawVertices[i].x), (float)(y - rawVertices[i].y));
} else {
path.lineTo((float)(x + rawVertices[i].x), (float)(y - rawVertices[i].y));
}
}
}
path.closePath();
}
// special cases
if(type == OVAL_SHAPE && diagonals) {
Pt0 = new GrappaPoint(
width * CIRCLE_XDIAG / 2.0,
height * CIRCLE_YDIAG / 2.0
);
Ppt.x = x + Pt0.x;
Ppt.y = y - Pt0.y;
Rpt.x = Ppt.x - 2.0 * Pt0.x;
Rpt.y = Ppt.y;
path.moveTo((float)Ppt.x, (float)Ppt.y);
path.lineTo((float)Rpt.x, (float)Rpt.y);
Ppt.y += (2.0 * Pt0.y) - 1.0;
Rpt.y = Ppt.y;
path.moveTo((float)Ppt.x, (float)Ppt.y);
path.lineTo((float)Rpt.x, (float)Rpt.y);
} else if(type == RECORD_SHAPE) {
if(rects != null) {
float tmp;
for(i = 0; i < rects.length; i += 4) {
if(rects[i] > rects[i+2]) {
tmp = rects[i];
rects[i] = rects[i+2];
rects[i+2] = tmp;
}
if(rects[i+1] > rects[i+3]) {
tmp = rects[i+1];
rects[i+1] = rects[i+3];
rects[i+3] = tmp;
}
if(!(rects[i] == rectsMin.x && rects[i+2] == rectsMax.x) || rects[i+1] != rectsMin.y) {
path.moveTo(rects[i],rects[i+1]);
path.lineTo(rects[i+2],rects[i+1]);
}
if(rects[i+2] != rectsMax.x || !(rects[i+1] == rectsMin.y && rects[i+3] == rectsMax.y)) {
path.moveTo(rects[i+2],rects[i+1]);
path.lineTo(rects[i+2],rects[i+3]);
}
if(!(rects[i] == rectsMin.x && rects[i+2] == rectsMax.x) || rects[i+3] != rectsMax.y) {
path.moveTo(rects[i+2],rects[i+3]);
path.lineTo(rects[i],rects[i+3]);
}
if(rects[i] != rectsMin.x || !(rects[i+1] == rectsMin.y && rects[i+3] == rectsMax.y)) {
path.moveTo(rects[i],rects[i+3]);
path.lineTo(rects[i],rects[i+1]);
}
}
}
}
}
////////////////////////////////////////////////////////////////////////
//
// Cloneable interface
//
////////////////////////////////////////////////////////////////////////
/**
* Creates a new object of the same class as this object.
*
* @return a clone of this instance.
* @exception OutOfMemoryError if there is not enough memory.
* @see java.lang.Cloneable
*/
public Object clone() {
try {
GrappaShape copy = (GrappaShape) super.clone();
copy.path = (GeneralPath) path.clone();
return copy;
} catch (CloneNotSupportedException e) {
// this shouldn’t happen, since we are Cloneable
throw new InternalError();
}
}
////////////////////////////////////////////////////////////////////////
//
// Shape interface
//
////////////////////////////////////////////////////////////////////////
public final boolean contains(double x, double y) {
return(path.contains(x, y));
}
public final boolean contains(double x, double y, double width, double height) {
return(path.contains(x, y, width, height));
}
public final boolean contains(Point2D p) {
return(path.contains(p));
}
public final boolean contains(Rectangle2D r) {
return(path.contains(r));
}
public final Rectangle getBounds() {
return(path.getBounds2D().getBounds());
}
public final Rectangle2D getBounds2D() {
return(path.getBounds2D());
}
/**
* Equivalent to getPathIterator(null).
*
* @see getPathIterator(AffineTransform)
*/
public final PathIterator getPathIterator() {
return path.getPathIterator(null);
}
public final PathIterator getPathIterator(AffineTransform at) {
return path.getPathIterator(at);
}
public final PathIterator getPathIterator(AffineTransform at, double flatness) {
return new FlatteningPathIterator(path.getPathIterator(at), flatness);
}
public final boolean intersects(double x, double y, double width, double height) {
return(path.intersects(x, y, width, height));
}
public final boolean intersects(Rectangle2D r) {
return(path.intersects(r));
}
}
att/grappa/GrappaSize.java
att/grappa/GrappaSize.java/*
* This software may only be used by you under license from AT&T Corp.
* (“AT&T”). A copy of AT&T’s Source Code Agreement is available at
* AT&T’s Internet website having the URL:
*
* If you received this software without first entering into a license
* with AT&T, you have an infringing copy of this software and cannot use
* it without violating AT&T’s intellectual property rights.
*/
package att.grappa;
/**
* This class extends java.awt.geom.Dimension2D and provides built-in
* string-to-Dimension2D and Dimension2D-to-string conversions suitable for Grappa.
*
* @version 1.2, 26 May 2005; Copyright 1996 – 2005 by AT&T Corp.
* @author John Mocenigo, Research @ AT&T Labs
*/
public class GrappaSize extends java.awt.geom.Dimension2D
{
/**
* The width of the Dimension.
*/
public double width;
/**
* The height of the Dimension.
*/
public double height;
/**
* Constructs and initializes a GrappaSize
with
* coordinates (0, 0).
*/
public GrappaSize() {
}
/**
* Constructs and initializes a GrappaSize
with the
* specified coordinates.
* @param width, height the coordinates to which to set the newly
* constructed GrappaSize
*/
public GrappaSize(double width, double height) {
this.width = width;
this.height = height;
}
/**
* Constructs and initializes a GrappaSize
with the
* coordinates derived from the specified String representation.
* The String format should be: “width,height”
* @param dimenString String representing the dimensions to which to
* set the newly constructed GrappaSize
*/
public GrappaSize(String dimenString) {
double[] coords = null;
try {
coords = GrappaSupport.arrayForTuple(dimenString);
}
catch(NumberFormatException nfe) {
throw new IllegalArgumentException(“coordinate string (” + dimenString + “) has a bad number format (” + nfe.getMessage() + “)”);
}
if(coords == null || coords.length != 2) {
throw new IllegalArgumentException(“coordinate string (” + dimenString + “) does not contain 2 valid coordinates”);
}
this.width = coords[0];
this.height = coords[1];
}
/**
* Returns the width.
*/
public double getWidth() {
return width;
}
/**
* Returns the height.
*/
public double getHeight() {
return height;
}
/**
* Sets the width and height.
*/
public void setSize(java.awt.geom.Dimension2D d) {
setSize(d.getWidth(), d.getHeight());
}
/**
* Sets the width and height.
*/
public void setSize(double width, double height) {
this.width = width;
this.height = height;
}
/**
* Provides a string representation of this object consistent
* with Grappa attributes.
*
* @return attribute-suitable string representation of this GrappaSize.
*/
public String toAttributeString() {
return(toFormattedString(“%p”));
}
/**
* Provides a formatted string representation of this object.
*
* @param format the format used to build the string (%p is the base directive suitable for a GrappaSize).
* @return a string representation of this GrappaSize.
*/
public String toFormattedString(String format) {
return(GrappaSupportPrintf.sprintf(new Object[] { format, this }));
}
/**
* Provides a generic string representation of this object.
*
* @return a generic string representation of this GrappaSize.
*/
public String toString() {
return(width+”,”+height);
}
}
att/grappa/GrappaStyle.java
att/grappa/GrappaStyle.java/*
* This software may only be used by you under license from AT&T Corp.
* (“AT&T”). A copy of AT&T’s Source Code Agreement is available at
* AT&T’s Internet website having the URL:
*
* If you received this software without first entering into a license
* with AT&T, you have an infringing copy of this software and cannot use
* it without violating AT&T’s intellectual property rights.
*/
package att.grappa;
import java.awt.*;
import java.awt.geom.*;
import java.util.Hashtable;
/**
* This class translates and encapsulates information provided by the style attribute.
*
* @version 1.2, 26 May 2005; Copyright 1996 – 2005 by AT&T Corp.
* @author John Mocenigo, Research @ AT&T Labs
*/
public class GrappaStyle
implements
GrappaConstants,
Cloneable
{
// element type associated with this style
private int elementType;
/**
* A style attribute with this string value gets set to the default
* style for the associated element type.
*/
public final static String DEFAULT_SET_STRING = “__default__”;
/**
* Integer value for indicating solid line info.
*/
public final static int STYLE_SOLID = 0;
/**
* Integer value for indicating dashed line info.
*/
public final static int STYLE_DASHED = 1;
/**
* Integer value for indicating dotted line info.
*/
public final static int STYLE_DOTTED = 2;
/**
* Integer value for indicating specific dashed line info.
*/
public final static int STYLE_DASH = 3;
/**
* Integer value for indicating dash phase info for a dashed line.
*/
public final static int STYLE_DASH_PHASE = 4;
/**
* Integer value for indicating line width info.
*/
public final static int STYLE_LINE_WIDTH = 5;
/**
* Integer value for indicating line color info.
*/
public final static int STYLE_LINE_COLOR = 6;
/**
* Integer value for indicating fill info.
*/
public final static int STYLE_FILLED = 7;
/**
* Integer value for indicating diagonal corner info.
*/
public final static int STYLE_DIAGONALS = 8;
/**
* Integer value for indicating rounded corner info.
*/
public final static int STYLE_ROUNDED = 9;
/**
* Integer value for indicating butt cap info.
*/
public final static int STYLE_CAP_BUTT = 10;
/**
* Integer value for indicating round cap info.
*/
public final static int STYLE_CAP_ROUND = 11;
/**
* Integer value for indicating square cap info.
*/
public final static int STYLE_CAP_SQUARE = 12;
/**
* Integer value for indicating bevel join info.
*/
public final static int STYLE_JOIN_BEVEL = 13;
/**
* Integer value for indicating miter join info.
*/
public final static int STYLE_JOIN_MITER = 14;
/**
* Integer value for indicating round miter info.
*/
public final static int STYLE_JOIN_ROUND = 15;
/**
* Integer value for indicating miter limit info.
*/
public final static int STYLE_MITER_LIMIT = 16;
/**
* Integer value for indicating fixed size info.
*/
public final static int STYLE_FIXED_SIZE = 17;
/**
* Integer value for indicating fill info.
*/
public final static int STYLE_INVIS = 18;
// for compatibility with dot (Grappa uses fontstyle)
/**
* Integer value for indicating bold font info (should use fontstyle)
*/
public final static int STYLE_OLD_BOLD = 100;
/**
* Integer value for indicating italic font info (should use fontstyle)
*/
public final static int STYLE_OLD_ITALIC = 101;
/**
* Integer value for indicating plain font info (should use fontstyle)
*/
public final static int STYLE_OLD_PLAIN = 102;
/**
* Line color default.
*/
public final static Color STYLE_LINE_COLOR_DEFAULT = GrappaColor.getColor(“black”,null);
/**
* Line style default.
*/
public final static int STYLE_LINE_STYLE_DEFAULT = STYLE_SOLID;
/**
* Line width default.
*/
public final static float STYLE_LINE_WIDTH_DEFAULT = 1;
/**
* Line cap default.
*/
public final static int STYLE_CAP_DEFAULT = BasicStroke.CAP_BUTT;
/**
* Line join default.
*/
public final static int STYLE_JOIN_DEFAULT = BasicStroke.JOIN_BEVEL;
/**
* Line miter default.
*/
public final static float STYLE_MITER_LIMIT_DEFAULT = 0;
/**
* Line dash default.
*/
public final static float[] STYLE_DASH_DEFAULT = null;
/**
* Line dash phase default.
*/
public final static float STYLE_DASH_PHASE_DEFAULT = 0;
/**
* Rounded corner default.
*/
public final static boolean STYLE_ROUNDED_DEFAULT = false;
/**
* Diagonal corner default.
*/
public final static boolean STYLE_DIAGONALS_DEFAULT = false;
/**
* Fill default.
*/
public final static boolean STYLE_FILLED_DEFAULT = false;
/**
* Invisibility default.
*/
public final static boolean STYLE_INVIS_DEFAULT = false;
/**
* Fixed size default.
*/
public final static boolean STYLE_FIXED_SIZE_DEFAULT = false;
static BasicStroke defaultStroke = new BasicStroke(STYLE_LINE_WIDTH_DEFAULT,STYLE_CAP_DEFAULT,STYLE_JOIN_DEFAULT,STYLE_MITER_LIMIT_DEFAULT,STYLE_DASH_DEFAULT,STYLE_DASH_PHASE_DEFAULT);
static String defaultStrokeString = generateStrokeString(STYLE_LINE_WIDTH_DEFAULT,STYLE_CAP_DEFAULT,STYLE_JOIN_DEFAULT,STYLE_MITER_LIMIT_DEFAULT,STYLE_DASH_DEFAULT,STYLE_DASH_PHASE_DEFAULT);
private static Hashtable styleTypes = new Hashtable(20);
private static Hashtable strokeCache = new Hashtable(4);
static {
styleTypes.put(“solid”,new Integer(STYLE_SOLID));
styleTypes.put(“dashed”,new Integer(STYLE_DASHED));
styleTypes.put(“dotted”,new Integer(STYLE_DOTTED));
styleTypes.put(“dash”,new Integer(STYLE_DASH));
styleTypes.put(“dashphase”,new Integer(STYLE_DASH_PHASE));
styleTypes.put(“dash_phase”,new Integer(STYLE_DASH_PHASE));
styleTypes.put(“width”,new Integer(STYLE_LINE_WIDTH));
styleTypes.put(“linewidth”,new Integer(STYLE_LINE_WIDTH));
styleTypes.put(“line_width”,new Integer(STYLE_LINE_WIDTH));
styleTypes.put(“setlinewidth”,new Integer(STYLE_LINE_WIDTH));
styleTypes.put(“color”,new Integer(STYLE_LINE_COLOR));
styleTypes.put(“linecolor”,new Integer(STYLE_LINE_COLOR));
styleTypes.put(“line_color”,new Integer(STYLE_LINE_COLOR));
styleTypes.put(“filled”,new Integer(STYLE_FILLED));
styleTypes.put(“invis”,new Integer(STYLE_INVIS));
styleTypes.put(“diagonals”,new Integer(STYLE_DIAGONALS));
styleTypes.put(“rounded”,new Integer(STYLE_ROUNDED));
styleTypes.put(“capbutt”,new Integer(STYLE_CAP_BUTT));
styleTypes.put(“cap_butt”,new Integer(STYLE_CAP_BUTT));
styleTypes.put(“capround”,new Integer(STYLE_CAP_ROUND));
styleTypes.put(“cap_round”,new Integer(STYLE_CAP_ROUND));
styleTypes.put(“capsquare”,new Integer(STYLE_CAP_SQUARE));
styleTypes.put(“cap_square”,new Integer(STYLE_CAP_SQUARE));
styleTypes.put(“joinbevel”,new Integer(STYLE_JOIN_BEVEL));
styleTypes.put(“join_bevel”,new Integer(STYLE_JOIN_BEVEL));
styleTypes.put(“joinmiter”,new Integer(STYLE_JOIN_MITER));
styleTypes.put(“join_miter”,new Integer(STYLE_JOIN_MITER));
styleTypes.put(“joinround”,new Integer(STYLE_JOIN_ROUND));
styleTypes.put(“join_round”,new Integer(STYLE_JOIN_ROUND));
styleTypes.put(“miterlimit”,new Integer(STYLE_MITER_LIMIT));
styleTypes.put(“miter_limit”,new Integer(STYLE_MITER_LIMIT));
styleTypes.put(“fixedsize”,new Integer(STYLE_FIXED_SIZE));
styleTypes.put(“fixed_size”,new Integer(STYLE_FIXED_SIZE));
// for compatibility with dot (these should be fontstyle for Grappa)
styleTypes.put(“bold”,new Integer(STYLE_OLD_BOLD));
styleTypes.put(“italic”,new Integer(STYLE_OLD_ITALIC));
styleTypes.put(“normal”,new Integer(STYLE_OLD_PLAIN));
styleTypes.put(“plain”,new Integer(STYLE_OLD_PLAIN));
strokeCache.put(defaultStrokeString, defaultStroke);
}
Color line_color = STYLE_LINE_COLOR_DEFAULT;
int line_style = STYLE_LINE_STYLE_DEFAULT;
float line_width = STYLE_LINE_WIDTH_DEFAULT;
int cap = STYLE_CAP_DEFAULT;
int join = STYLE_JOIN_DEFAULT;
float miter_limit = STYLE_MITER_LIMIT_DEFAULT;
float[] dash = STYLE_DASH_DEFAULT;
float dash_phase = STYLE_DASH_PHASE_DEFAULT;
boolean rounded = STYLE_ROUNDED_DEFAULT;
boolean diagonals = STYLE_DIAGONALS_DEFAULT;
boolean filled = STYLE_FILLED_DEFAULT;
boolean invis = STYLE_INVIS_DEFAULT;
boolean fixed_size = STYLE_FIXED_SIZE_DEFAULT;
Integer font_style = null;
BasicStroke stroke = defaultStroke;
////////////////////////////////////////////////////////////////////////
//
// Constructors
//
////////////////////////////////////////////////////////////////////////
/**
* Constructs a new GrappaStyle
object from a style
* description string.
*
* @param type element type to associate with this style.
* @param style the String
that specifies the style info.
* format is: style1,style2(extra2),…,styleN.
*/
public GrappaStyle(int type, String style) {
if((type&(Grappa.NODE|Grappa.EDGE|Grappa.SUBGRAPH|Grappa.SYSTEM)) != type) {
throw new RuntimeException(“type must specify node, edge or subgraph”);
}
this.elementType = type;
updateStyle(style);
}
////////////////////////////////////////////////////////////////////////
//
// Public methods
//
////////////////////////////////////////////////////////////////////////
/**
* Update this GrappaStyle based on the supplied style string.
*
* @param style a style specification
*/
public void updateStyle(String style) {
stroke = defaultStroke;
line_color = STYLE_LINE_COLOR_DEFAULT;
line_style = STYLE_LINE_STYLE_DEFAULT;
line_width = STYLE_LINE_WIDTH_DEFAULT;
cap = STYLE_CAP_DEFAULT;
join = STYLE_JOIN_DEFAULT;
miter_limit = STYLE_MITER_LIMIT_DEFAULT;
dash = STYLE_DASH_DEFAULT;;
dash_phase = STYLE_DASH_PHASE_DEFAULT;
rounded = STYLE_ROUNDED_DEFAULT;
diagonals = STYLE_DIAGONALS_DEFAULT;
filled = STYLE_FILLED_DEFAULT;
invis = STYLE_INVIS_DEFAULT;
fixed_size = STYLE_FIXED_SIZE_DEFAULT;
font_style = null;
if(style == null) return;
int len = style.length();
if(len == 0 || style.equals(GrappaStyle.DEFAULT_SET_STRING)) return;
String option_string = null;
Object option_obj = null;
int option = -1;
int last_option = -1;
boolean in_parens = false;
boolean keyword_ok = true;
boolean parens_ok = false;
int i = 0, offset = 0;
char c;
while(i
if(c == ‘(‘) pcnt++;
else if(c == ‘)’) pcnt–;
i++;
}
} else {
while(i < len && (c = style.charAt(i)) != ',' && c != ' ' && c != '(' && c != ')') i++;
}
option_string = style.substring(offset,i);
if(in_parens) {
if(last_option == -1) {
throw new RuntimeException("style attribute modifier (" + option_string + ") is unexpected");
}
switch(last_option) {
case STYLE_DASH:
line_style = last_option;
try {
dash = GrappaSupport.floatArrayForTuple(option_string);
} catch(NumberFormatException nfe) {
throw new RuntimeException("dash style attribute modifier (" + option_string + ") is not a comma-delimited floating point tuple");
}
break;
case STYLE_DASH_PHASE:
try {
dash_phase = Float.valueOf(option_string).floatValue();
} catch(NumberFormatException nfe) {
throw new RuntimeException("dash phase style attribute modifier (" + option_string + ") is not a floating point number");
}
break;
case STYLE_LINE_WIDTH:
try {
line_width = Float.valueOf(option_string).floatValue();
} catch(NumberFormatException nfe) {
throw new RuntimeException("line width style attribute modifier (" + option_string + ") is not a floating point number");
}
break;
case STYLE_MITER_LIMIT:
try {
miter_limit = Float.valueOf(option_string).floatValue();
} catch(NumberFormatException nfe) {
throw new RuntimeException("miter limit style attribute modifier (" + option_string + ") is not a floating point number");
}
break;
case STYLE_LINE_COLOR:
line_color = GrappaColor.getColor(option_string,null);
break;
case STYLE_FILLED:
filled = Boolean.valueOf(option_string).booleanValue();
break;
case STYLE_INVIS:
invis = Boolean.valueOf(option_string).booleanValue();
break;
case STYLE_DIAGONALS:
diagonals = Boolean.valueOf(option_string).booleanValue();
break;
case STYLE_ROUNDED:
rounded = Boolean.valueOf(option_string).booleanValue();
break;
case STYLE_FIXED_SIZE:
fixed_size = Boolean.valueOf(option_string).booleanValue();
break;
case STYLE_OLD_BOLD:
case STYLE_OLD_ITALIC:
case STYLE_OLD_PLAIN:
case STYLE_SOLID:
case STYLE_DASHED:
case STYLE_DOTTED:
case STYLE_CAP_BUTT:
case STYLE_CAP_ROUND:
case STYLE_CAP_SQUARE:
case STYLE_JOIN_BEVEL:
case STYLE_JOIN_MITER:
case STYLE_JOIN_ROUND:
default:
throw new RuntimeException("style attribute (" + option_string + ") has bad format");
}
last_option = -1;
} else {
option_obj = styleTypes.get(option_string.toLowerCase());
if(option_obj == null || !(option_obj instanceof Integer) ) {
throw new RuntimeException("style attribute (" + option_string + ") is unrecognized or badly implemented");
}
option = ((Integer)option_obj).intValue();
last_option = -1;
switch(option) {
case STYLE_SOLID:
line_style = option;
dash = null;
dash_phase = 0;
break;
case STYLE_DASHED:
line_style = option;
dash = new float[] { 12, 12 };
dash_phase = 0;
break;
case STYLE_DOTTED:
line_style = option;
dash = new float[] { 2, 2 };
dash_phase = 0;
break;
case STYLE_FILLED:
last_option = option;
filled = true;
break;
case STYLE_INVIS:
last_option = option;
invis = true;
break;
case STYLE_DIAGONALS:
last_option = option;
diagonals = true;
break;
case STYLE_ROUNDED:
last_option = option;
rounded = true;
break;
case STYLE_CAP_BUTT:
cap = BasicStroke.CAP_BUTT;
break;
case STYLE_CAP_ROUND:
cap = BasicStroke.CAP_ROUND;
break;
case STYLE_CAP_SQUARE:
cap = BasicStroke.CAP_SQUARE;
break;
case STYLE_JOIN_BEVEL:
cap = BasicStroke.JOIN_BEVEL;
break;
case STYLE_JOIN_MITER:
cap = BasicStroke.JOIN_MITER;
break;
case STYLE_JOIN_ROUND:
cap = BasicStroke.JOIN_ROUND;
break;
case STYLE_FIXED_SIZE:
last_option = option;
fixed_size = true;
break;
case STYLE_OLD_BOLD:
font_style = new Integer(Font.BOLD);
break;
case STYLE_OLD_ITALIC:
font_style = new Integer(Font.ITALIC);
break;
case STYLE_OLD_PLAIN:
font_style = new Integer(Font.PLAIN);
break;
case STYLE_DASH:
case STYLE_DASH_PHASE:
case STYLE_LINE_WIDTH:
case STYLE_LINE_COLOR:
case STYLE_MITER_LIMIT:
last_option = option;
break;
default:
throw new RuntimeException("style attribute (" + option_string + ") has bad format");
}
if(last_option != -1) parens_ok = true;
}
}
}
if(in_parens) {
throw new RuntimeException("style attribute has unmatched left parenthesis");
}
String strokeString = generateStrokeString(line_width,cap,join,miter_limit,dash,dash_phase);
if((stroke = (BasicStroke)strokeCache.get(strokeString)) == null) {
stroke = new BasicStroke(line_width,cap,join,miter_limit,dash,dash_phase);
strokeCache.put(strokeString,stroke);
}
}
private static String generateStrokeString(
float lineWidth,
int capType,
int joinType,
float miterLimit,
float[] dashSpec,
float dashPhase
) {
StringBuffer strokeStringBuffer = new StringBuffer();
strokeStringBuffer.append(lineWidth);
strokeStringBuffer.append(",");
strokeStringBuffer.append(capType);
strokeStringBuffer.append(",");
strokeStringBuffer.append(joinType);
strokeStringBuffer.append(",");
strokeStringBuffer.append(miterLimit);
strokeStringBuffer.append(",");
if(dashSpec == null) {
strokeStringBuffer.append("null");
} else {
strokeStringBuffer.append("{");
strokeStringBuffer.append(dashSpec[0]);
for(int i = 1; i < dashSpec.length; i++) {
strokeStringBuffer.append(",");
strokeStringBuffer.append(dashSpec[i]);
}
strokeStringBuffer.append("}");
}
strokeStringBuffer.append(",");
strokeStringBuffer.append(dashPhase);
return(strokeStringBuffer.toString());
}
/**
* Provides a string representation of this object consistent
* with Grappa attributes.
*
* @return attribute-suitable string representation of this GrappaStyle.
*/
public String toAttributeString() {
return(generateStyleString(line_color,line_style,line_width,cap,join,miter_limit,dash,dash_phase,rounded,diagonals,filled,invis,fixed_size,font_style,false,elementType));
}
/**
* Provides a generic string representation of this object.
*
* @return a generic string representation of this GrappaStyle.
*/
public String toString() {
return(generateStyleString(line_color,line_style,line_width,cap,join,miter_limit,dash,dash_phase,rounded,diagonals,filled,invis,fixed_size,font_style,true,elementType));
}
private static String generateStyleString(
Color color,
int lineStyle,
float lineWidth,
int capType,
int joinType,
float miterLimit,
float[] dashSpec,
float dashPhase,
boolean roundedFlag,
boolean diagonalsFlag,
boolean filledFlag,
boolean invisFlag,
boolean fixedSizeFlag,
Integer fontStyle,
boolean showAll,
int type
) {
StringBuffer styleStringBuffer = null;
String tmpstr = null;
Object[] args = { "%g", null };
if(
showAll
||
(
color != STYLE_LINE_COLOR_DEFAULT
&&
STYLE_LINE_COLOR_DEFAULT != null
&&
!STYLE_LINE_COLOR_DEFAULT.equals(color)
)
) {
if(styleStringBuffer == null) {
styleStringBuffer = new StringBuffer();
} else {
styleStringBuffer.append(',');
}
styleStringBuffer.append("lineColor(");
if((tmpstr = GrappaColor.getColorName(color)) == null) {
float[] hsb = Color.RGBtoHSB(color.getRed(),color.getGreen(),color.getBlue(),null);
//styleStringBuffer.append(hsb[0]);
//styleStringBuffer.append(',');
//styleStringBuffer.append(hsb[1]);
//styleStringBuffer.append(',');
//styleStringBuffer.append(hsb[2]);
styleStringBuffer.append(GrappaSupportPrintf.sprintf(new Object[] { "%g,%g,%g", new Float(hsb[0]), new Float(hsb[1]), new Float(hsb[2]) }));
} else {
styleStringBuffer.append(tmpstr);
}
styleStringBuffer.append(')');
}
if(
showAll
||
lineStyle != STYLE_LINE_STYLE_DEFAULT
) {
if(styleStringBuffer == null) {
styleStringBuffer = new StringBuffer();
} else {
styleStringBuffer.append(',');
}
switch(lineStyle) {
case STYLE_SOLID:
styleStringBuffer.append("solid");
break;
case STYLE_DASHED:
styleStringBuffer.append("dashed");
break;
case STYLE_DOTTED:
styleStringBuffer.append("dotted");
break;
case STYLE_DASH:
if(dashSpec == null) {
styleStringBuffer.append("solid");
} else {
styleStringBuffer.append("dash(");
//styleStringBuffer.append(dashSpec[0]);
args[1] = new Float(dashSpec[0]);
styleStringBuffer.append(GrappaSupportPrintf.sprintf(args));
for(int i = 1; i < dashSpec.length; i++) {
styleStringBuffer.append(',');
//styleStringBuffer.append(dashSpec[i]);
args[1] = new Float(dashSpec[i]);
styleStringBuffer.append(GrappaSupportPrintf.sprintf(args));
}
styleStringBuffer.append(')');
}
break;
default:
throw new InternalError("unexpected lineStyle (" + lineStyle + ")");
}
}
if(
showAll
||
lineWidth != STYLE_LINE_WIDTH_DEFAULT
) {
if(styleStringBuffer == null) {
styleStringBuffer = new StringBuffer();
} else {
styleStringBuffer.append(',');
}
styleStringBuffer.append("lineWidth(");
//styleStringBuffer.append(lineWidth);
args[1] = new Float(lineWidth);
styleStringBuffer.append(GrappaSupportPrintf.sprintf(args));
styleStringBuffer.append(')');
}
if(
showAll
||
capType != STYLE_CAP_DEFAULT
) {
if(styleStringBuffer == null) {
styleStringBuffer = new StringBuffer();
} else {
styleStringBuffer.append(',');
}
switch(capType) {
case BasicStroke.CAP_BUTT:
styleStringBuffer.append("capButt");
break;
case BasicStroke.CAP_ROUND:
styleStringBuffer.append("capRound");
break;
case BasicStroke.CAP_SQUARE:
styleStringBuffer.append("capSquare");
break;
default:
throw new InternalError("unexpected cap type (" + capType + ")");
}
}
if(
showAll
||
joinType != STYLE_JOIN_DEFAULT
) {
if(styleStringBuffer == null) {
styleStringBuffer = new StringBuffer();
} else {
styleStringBuffer.append(',');
}
switch(joinType) {
case BasicStroke.JOIN_BEVEL:
styleStringBuffer.append("joinBevel");
break;
case BasicStroke.JOIN_MITER:
styleStringBuffer.append("joinMiter");
break;
case BasicStroke.JOIN_ROUND:
styleStringBuffer.append("joinRound");
break;
default:
throw new InternalError("unexpected join type (" + joinType + ")");
}
}
if(
showAll
||
miterLimit != STYLE_MITER_LIMIT_DEFAULT
) {
if(styleStringBuffer == null) {
styleStringBuffer = new StringBuffer();
} else {
styleStringBuffer.append(',');
}
styleStringBuffer.append("miterLimit(");
//styleStringBuffer.append(miterLimit);
args[1] = new Float(miterLimit);
styleStringBuffer.append(GrappaSupportPrintf.sprintf(args));
styleStringBuffer.append(')');
}
if(
showAll
||
dashPhase != STYLE_DASH_PHASE_DEFAULT
) {
if(styleStringBuffer == null) {
styleStringBuffer = new StringBuffer();
} else {
styleStringBuffer.append(',');
}
styleStringBuffer.append("dashPhase(");
//styleStringBuffer.append(dashPhase);
args[1] = new Float(dashPhase);
styleStringBuffer.append(GrappaSupportPrintf.sprintf(args));
styleStringBuffer.append(')');
}
if(
(
type > 0
&&
(type&Grappa.NODE) == Grappa.NODE
)
&&
(
showAll
||
roundedFlag != STYLE_ROUNDED_DEFAULT
)
) {
if(styleStringBuffer == null) {
styleStringBuffer = new StringBuffer();
} else {
styleStringBuffer.append(‘,’);
}
if(roundedFlag) {
styleStringBuffer.append(“rounded”);
} else {
styleStringBuffer.append(“rounded(false)”);
}
}
if(
(
type > 0
&&
(type&Grappa.NODE) == Grappa.NODE
)
&&
(
showAll
||
diagonalsFlag != STYLE_DIAGONALS_DEFAULT
)
) {
if(styleStringBuffer == null) {
styleStringBuffer = new StringBuffer();
} else {
styleStringBuffer.append(‘,’);
}
if(diagonalsFlag) {
styleStringBuffer.append(“diagonals”);
} else {
styleStringBuffer.append(“diagonals(false)”);
}
}
if(
(
type > 0
&&
(type&(Grappa.NODE|Grappa.SUBGRAPH)) != 0
)
&&
(
showAll
||
filledFlag != STYLE_FILLED_DEFAULT
)
) {
if(styleStringBuffer == null) {
styleStringBuffer = new StringBuffer();
} else {
styleStringBuffer.append(‘,’);
}
if(filledFlag) {
styleStringBuffer.append(“filled”);
} else {
styleStringBuffer.append(“filled(false)”);
}
}
if(
(
type > 0
&&
(type&(Grappa.NODE|Grappa.EDGE|Grappa.SUBGRAPH)) != 0
)
&&
(
showAll
||
invisFlag != STYLE_INVIS_DEFAULT
)
) {
if(styleStringBuffer == null) {
styleStringBuffer = new StringBuffer();
} else {
styleStringBuffer.append(‘,’);
}
if(invisFlag) {
styleStringBuffer.append(“invis”);
} else {
styleStringBuffer.append(“invis(false)”);
}
}
if(
showAll
||
fixedSizeFlag != STYLE_FIXED_SIZE_DEFAULT
) {
if(styleStringBuffer == null) {
styleStringBuffer = new StringBuffer();
} else {
styleStringBuffer.append(‘,’);
}
if(fixedSizeFlag) {
styleStringBuffer.append(“fixedSize”);
} else {
styleStringBuffer.append(“fixedSize(false)”);
}
}
if(
fontStyle != null
) {
if(styleStringBuffer == null) {
styleStringBuffer = new StringBuffer();
} else {
styleStringBuffer.append(‘,’);
}
if(fontStyle.intValue() == Font.BOLD) {
styleStringBuffer.append(“bold”);
} else if(fontStyle.intValue() == Font.ITALIC) {
styleStringBuffer.append(“italic”);
} else {
styleStringBuffer.append(“plain”);
}
}
if(styleStringBuffer == null) {
tmpstr = “”; // or set it null?
} else {
tmpstr = styleStringBuffer.toString();
}
return(tmpstr);
}
/**
* Get the line color.
*
* @return the line color.
*/
public Color getLineColor() {
return line_color;
}
/**
* Get the line style.
*
* @return the line style.
*/
public int getLineStyle() {
return line_style;
}
/**
* Get the line width.
*
* @return the line width.
*/
public float getLineWidth() {
return line_width;
}
/**
* Get the cap style.
*
* @return the cap style.
*/
public int getCapStyle() {
return cap;
}
/**
* Get the join style.
*
* @return the join style.
*/
public int getJoinStyle() {
return join;
}
/**
* Get the miter limit.
*
* @return the miter limit.
*/
public float getMiterLimit() {
return miter_limit;
}
/**
* Get the dash specification.
*
* @return the dash specification.
*/
public float[] getDash() {
if(dash == null) {
return(null);
}
return((float[])(dash.clone()));
}
/**
* Get the dash phase.
*
* @return the dash phase.
*/
public float getDashPhase() {
return dash_phase;
}
/**
* Get the rounded corner specification.
*
* @return the rounded corner specification color (true indicates rounded corners).
*/
public boolean getRounded() {
return rounded;
}
/**
* Get the diagonal corner specification.
*
* @return the diagonal corner specification color (true indicates diagonal corners).
*/
public boolean getDiagonals() {
return diagonals;
}
/**
* Get the fill specification.
*
* @return the fill specification (true indicates filling should occur).
*/
public boolean getFilled() {
return filled;
}
/**
* Get the invisibility specification.
*
* @return the invisibility specification (true indicates element is invisible).
*/
public boolean getInvis() {
return invis;
}
/**
* Get the fixed size specification.
*
* @return the fixed size specification (true indicates that fixed size drawing is requested).
*/
public boolean getFixedSize() {
return fixed_size;
}
/**
* Get the font style.
* Actually, the fontstyle attribute should be used for
* font style dealings rather than the style attribute, but
* the latter is permitted for backward compatibility with dot.
*
* @return the font style.
*/
public int getFontStyle() {
if(font_style == null) return(Font.PLAIN);
return font_style.intValue();
}
////////////////////////////////////////////////////////////////////////
//
// Cloneable interface
//
////////////////////////////////////////////////////////////////////////
/**
* Creates a new object of the same class as this object.
*
* @return a clone of this instance.
* @exception OutOfMemoryError if there is not enough memory.
* @see java.lang.Cloneable
*/
public Object clone() {
try {
GrappaStyle copy = (GrappaStyle) super.clone();
copy.dash = getDash();
return copy;
} catch (CloneNotSupportedException e) {
// this shouldn’t happen, since we are Cloneable
throw new InternalError();
}
}
}
att/grappa/GrappaSupport.java
att/grappa/GrappaSupport.java/*
* This software may only be used by you under license from AT&T Corp.
* (“AT&T”). A copy of AT&T’s Source Code Agreement is available at
* AT&T’s Internet website having the URL:
*
* If you received this software without first entering into a license
* with AT&T, you have an infringing copy of this software and cannot use
* it without violating AT&T’s intellectual property rights.
*/
package att.grappa;
import java.io.*;
import java.util.*;
import java.awt.geom.*;
/**
* A class providing some supports function for Grappa.
*
* @version 1.2, 26 May 2005; Copyright 1996 – 2005 by AT&T Corp.
* @author John Mocenigo and Rich Drechsler, Research @ AT&T Labs
*/
public abstract
class GrappaSupport
implements GrappaConstants
{
///////////////////////////////////////////////////////////////////////////
//
// The ctypes type stuff is courtesy of Rich Drechsler of AT&T Labs.
//
///////////////////////////////////////////////////////////////////////////
private static final short CN = 0x01; // control
private static final short WS = 0x02; // white space
private static final short SP = 0x04; // space
private static final short PU = 0x08; // punctuation
private static final short DG = 0x10; // digit
private static final short OD = 0x20; // octal digit
private static final short UC = 0x40; // upper case
private static final short HD = 0x80; // hex digit
private static final short LC = 0x100; // lower case
private static final short ctype[] = {
CN, CN, CN, CN, CN, CN, CN, CN,
CN, CN|WS, CN|WS, CN|WS, CN|WS, CN|WS, CN, CN,
CN, CN, CN, CN, CN, CN, CN, CN,
CN, CN, CN, CN, CN, CN, CN, CN,
WS|SP, PU, PU, PU, PU, PU, PU, PU,
PU, PU, PU, PU, PU, PU, PU, PU,
DG|OD, DG|OD, DG|OD, DG|OD, DG|OD, DG|OD, DG|OD, DG|OD,
DG, DG, PU, PU, PU, PU, PU, PU,
PU, UC|HD, UC|HD, UC|HD, UC|HD, UC|HD, UC|HD, UC,
UC, UC, UC, UC, UC, UC, UC, UC,
UC, UC, UC, UC, UC, UC, UC, UC,
UC, UC, UC, PU, PU, PU, PU, PU,
PU, LC|HD, LC|HD, LC|HD, LC|HD, LC|HD, LC|HD, LC,
LC, LC, LC, LC, LC, LC, LC, LC,
LC, LC, LC, LC, LC, LC, LC, LC,
LC, LC, LC, PU, PU, PU, PU, CN,
};
private static final short ALPHA = (UC|LC);
private static final short ALNUM = (UC|LC|DG);
private static final short GRAPH = (ALNUM|PU);
private static final short PRINT = (GRAPH|SP);
private static final short ODIGIT = (OD);
private static final short XDIGIT = (DG|HD);
private static final short LOWERTOUPPER = ‘A’ – ‘a’;
private static final short UPPERTOLOWER = ‘a’ – ‘A’;
///////////////////////////////////////////////////////////////////////////
//
// GrappaSupport
//
///////////////////////////////////////////////////////////////////////////
/**
* for ASCII only
*/
static boolean
isalnum(int ch) {
return(isascii(ch) && (ctype[ch]&ALNUM) != 0);
}
///////////////////////////////////////////////////////////////////////////
/**
* for ASCII only
*/
static boolean
isalpha(int ch) {
return(isascii(ch) && (ctype[ch]&ALPHA) != 0);
}
///////////////////////////////////////////////////////////////////////////
/**
* for ASCII only
*/
static boolean
isascii(int ch) {
return(ch >= 0 && ch < 128);
}
///////////////////////////////////////////////////////////////////////////
/**
* for ASCII only
*/
static boolean
iscntrl(int ch) {
return(isascii(ch) && (ctype[ch]&CN) != 0);
}
///////////////////////////////////////////////////////////////////////////
/**
* for ASCII only
*/
static boolean
isdigit(int ch) {
return(isascii(ch) && (ctype[ch]&DG) != 0);
}
///////////////////////////////////////////////////////////////////////////
/**
* for ASCII only
*/
static boolean
isgraph(int ch) {
return(isascii(ch) && (ctype[ch]&DG) != 0);
}
///////////////////////////////////////////////////////////////////////////
/**
* for ASCII only
*/
static boolean
islower(int ch) {
return(isascii(ch) && (ctype[ch]&LC) != 0);
}
///////////////////////////////////////////////////////////////////////////
/**
* for ASCII only
*/
static boolean
isoctal(int ch) {
return(isascii(ch) && (ctype[ch]&ODIGIT) != 0);
}
///////////////////////////////////////////////////////////////////////////
/**
* for ASCII only
*/
static boolean
isprint(int ch) {
return(isascii(ch) && (ctype[ch]&PRINT) != 0);
}
///////////////////////////////////////////////////////////////////////////
/**
* for ASCII only
*/
static boolean
ispunct(int ch) {
return(isascii(ch) && (ctype[ch]&PU) != 0);
}
///////////////////////////////////////////////////////////////////////////
/**
* for ASCII only
*/
static boolean
isspace(int ch) {
return(isascii(ch) && (ctype[ch]&WS) != 0);
}
///////////////////////////////////////////////////////////////////////////
/**
* for ASCII only
*/
static boolean
isupper(int ch) {
return(isascii(ch) && (ctype[ch]&UC) != 0);
}
///////////////////////////////////////////////////////////////////////////
/**
* for ASCII only
*/
static boolean
isxdigit(int ch) {
return(isascii(ch) && (ctype[ch]&XDIGIT) != 0);
}
///////////////////////////////////////////////////////////////////////////
/**
* for ASCII only
*/
static int
tolower(int ch) {
return(isupper(ch) ? ch + UPPERTOLOWER : ch);
}
///////////////////////////////////////////////////////////////////////////
/**
* for ASCII only
*/
static int
toupper(int ch) {
return(islower(ch) ? ch + LOWERTOUPPER : ch);
}
///////////////////////////////////////////////////////////////////////////
static String[]
strsplit(String tuple) throws IllegalArgumentException {
if(tuple == null) throw new IllegalArgumentException("supplied split string is null");
StringTokenizer st = new StringTokenizer(tuple,",",false);
String[] array = new String[st.countTokens()];
int i = 0;
while(st.hasMoreTokens()) {
array[i++] = st.nextToken();
}
return array;
}
///////////////////////////////////////////////////////////////////////////
static float[]
floatArrayForTuple(String tuple) throws IllegalArgumentException, NumberFormatException {
if(tuple == null) throw new IllegalArgumentException("supplied tuple string is null");
StringTokenizer st = new StringTokenizer(tuple,", \t",false);
float[] array = new float[st.countTokens()];
int i = 0;
while(st.hasMoreTokens()) {
array[i++] = Float.valueOf(st.nextToken()).floatValue();
}
return array;
}
///////////////////////////////////////////////////////////////////////////
static double[]
arrayForTuple(String tuple) throws IllegalArgumentException, NumberFormatException {
if(tuple == null) throw new IllegalArgumentException("supplied tuple string is null");
StringTokenizer st = new StringTokenizer(tuple,", \t",false);
double[] array = new double[st.countTokens()];
int i = 0;
while(st.hasMoreTokens()) {
array[i++] = Double.valueOf(st.nextToken()).doubleValue();
}
return array;
}
///////////////////////////////////////////////////////////////////////////
/**
* Converts a string to an integer edge direction.
* The string is first canonicalized (converted to lower case and
* non-alphanumerics are removed) then compared to none, back, forward
* or both. A match returns GrappaLine.NONE_ARROW_EDGE,
* GrappaLine.HEAD_ARROW_EDGE, GrappaLine.TAIL_ARROW_EDGE or
* GrappaLine.BOTH_ARROW_EDGE, respectively. When there is no match,
* GrappaLine.NONE_ARROW_EDGE is returned.
*
* @param direction a string representing an edge direction
*
* @return an integer representation of the supplied edge direction
*/
public static int xlateDirString(String direction) {
if(direction != null) {
String dir = canonize(direction);
if(dir.equals("forward")) {
return GrappaLine.TAIL_ARROW_EDGE;
} else if(dir.equals("back")) {
return GrappaLine.HEAD_ARROW_EDGE;
} else if(dir.equals("both")) {
return GrappaLine.BOTH_ARROW_EDGE;
}
}
return GrappaLine.NONE_ARROW_EDGE;
}
/**
* Converts an integer edge direction value to a string representation.
* Only GrappaLine.NONE_ARROW_EDGE, GrappaLine.HEAD_ARROW_EDGE,
* GrappaLine.TAIL_ARROW_EDGE and GrappaLine.BOTH_ARROW_EDGE are
* understood, all others are taken to mean GrappaLine.NONE_ARROW_EDGE.
*
* @param direction an integer representing an edge direction
*
* @return a string representation of the supplied edge direction
*/
public static String xlateDir(int direction) {
String retstr = null;
if(direction == GrappaLine.TAIL_ARROW_EDGE) {
retstr = "forward";
} else if(direction == GrappaLine.HEAD_ARROW_EDGE) {
retstr = "back";
} else if(direction == GrappaLine.BOTH_ARROW_EDGE) {
retstr = "both";
} else {
retstr = "none";
}
return retstr;
}
/**
* Converts a string to an integer font style.
* The string is first canonicalized (converted to lower case and
* non-alphanumerics are removed) then compared to italic, bold or
* bolditalic. A match returns Font.ITALIC, Font.BOLD, or a bitwise
* OR-ing of the two, respectively. When there is no match, Font.PLAIN
* is returned.
*
* @param fontstyle a string representing a font style
*
* @return an integer representation of the supplied font style string
*/
public static int xlateFontStyleString(String fontstyle) {
if(fontstyle != null) {
String style = canonize(fontstyle);
if(style.equals("italic")) {
return java.awt.Font.ITALIC;
} else if(style.equals("bold")) {
return java.awt.Font.BOLD;
} else if(style.equals("bolditalic")) {
return (java.awt.Font.BOLD|java.awt.Font.ITALIC);
}
}
return java.awt.Font.PLAIN;
}
/**
* Converts an integer font style value to a string representation.
* Only Font.ITALIC, Font.BOLD, and (Font.BOLD|Font.ITALIC) are
* understood, all others are taken to mean Font.PLAIN.
*
* @param fontstyle an integer representing a font style
*
* @return a string representation of the supplied font style value
*/
public static String xlateFontStyle(int fontstyle) {
String retstr = null;
if(fontstyle == java.awt.Font.ITALIC) {
retstr = "italic";
} else if(fontstyle == java.awt.Font.BOLD) {
retstr = "bold";
} else if(fontstyle == (java.awt.Font.BOLD|java.awt.Font.ITALIC)) {
retstr = "bolditalic";
} else {
retstr = "normal";
}
return retstr;
}
/**
* Canonize string by converting to lower-case and removing all
* non-letter, non-digit characters.
*
* @param input the string to be canonized
*
* @return the canonized string
*/
public static String canonize(String input) {
if(input == null) return null;
char[] array = input.toCharArray();
int pos = 0;
for(int i = 0; i < array.length; i++) {
if(Character.isLetterOrDigit(array[i])) {
array[pos++] = Character.toLowerCase(array[i]);
}
}
if(pos == 0) return("");
return new String(array,0,pos);
}
/**
* Creates a GrappaBox from the coordinates of any two opposing corners.
*
* @param x1 x-coordinate of corner number 1.
* @param y1 x-coordinate of corner number 1.
* @param x2 x-coordinate of corner number 2, which is opposite corner 1.
* @param y2 x-coordinate of corner number 2, which is opposite corner 1.
* @return a GrappaBox generated the possibly-reordered coordinates.
*/
public static GrappaBox boxFromCorners(double x1, double y1, double x2, double y2) {
return(boxFromCorners(null, x1, y1, x2, y2));
}
/**
* Creates a GrappaBox from the coordinates of any two opposing corners.
*
* @param box if non-null, the coordinates of this box are changed and this box is returned, otherwise a new box is created.
* @param x1 x-coordinate of corner number 1.
* @param y1 x-coordinate of corner number 1.
* @param x2 x-coordinate of corner number 2, which is opposite corner 1.
* @param y2 x-coordinate of corner number 2, which is opposite corner 1.
* @return a GrappaBox generated the possibly-reordered coordinates.
*/
public static GrappaBox boxFromCorners(GrappaBox box, double x1, double y1, double x2, double y2) {
if(box == null) {
box = new GrappaBox();
}
box.x = x1 < x2 ? x1 : x2;
box.y = y1 < y2 ? y1 : y2;
box.width = x1 < x2 ? x2 - x1 : x1 - x2;
box.height = y1 < y2 ? y2 - y1 : y1 - y2;
return(box);
}
/**
* Find an element in the supplied subgraph that contains the given point.
* The last element encoutered is returned from a search of first
* subgraphs, then edges, then nodes. The ordering within a set of elements
* (e.g., nodes) is indeterminate.
*
* @param subg the subgraph to be searched.
* @param pt the point of the search.
* @return an element containing the point, or null.
*/
public static Element findContainingElement(Subgraph subg, Point2D pt) {
Element elem = null;
Rectangle2D bb = subg.getBoundingBox();
GrappaNexus grappaNexus = null;
if(bb.contains(pt)) {
elem = subg;
Enumeration enm;
Element subelem = null;
enm = subg.subgraphElements();
while(enm.hasMoreElements()) {
if((subelem = findContainingElement((Subgraph)(enm.nextElement()), pt)) != null) {
elem = subelem;
}
}
enm = subg.edgeElements();
Edge edge;
while(enm.hasMoreElements()) {
edge = (Edge)enm.nextElement();
if((grappaNexus = edge.grappaNexus) == null) continue;
if(grappaNexus.rawBounds2D().contains(pt)) {
if(grappaNexus.contains(pt)) {
elem = edge;
}
}
}
enm = subg.nodeElements();
Node node;
while(enm.hasMoreElements()) {
node = (Node)enm.nextElement();
if((grappaNexus = node.grappaNexus) == null) continue;
if(grappaNexus.rawBounds2D().contains(pt)) {
if(grappaNexus.contains(pt)) {
elem = node;
}
}
}
}
return(elem);
}
/**
* Find the elements in the supplied subgraph that are contained in
* the given box.
*
* @param subg the subgraph to be searched.
* @param pt the container box.
* @return a vector whose components may be single elements or another
* vector of this same type with the property that all the elements
* in the vector (when eventually unravelled) are contained in
* the supplied box.
*/
public static Vector findContainedElements(Subgraph subg, GrappaBox box) {
Vector elems = null;
Rectangle2D bb = subg.getBoundingBox();
GrappaNexus grappaNexus = null;
if(box.contains(bb)) {
return subg.vectorOfElements(Grappa.SUBGRAPH|Grappa.NODE|Grappa.EDGE);
} else if(box.intersects(bb)) {
Enumeration enm;
Vector subelems = null;
enm = subg.subgraphElements();
while(enm.hasMoreElements()) {
if((subelems = findContainedElements((Subgraph)(enm.nextElement()), box)) != null) {
if(elems == null) {
elems = new Vector();
}
elems.add(subelems);
}
}
enm = subg.edgeElements();
Edge edge;
while(enm.hasMoreElements()) {
edge = (Edge)enm.nextElement();
if((grappaNexus = edge.grappaNexus) == null) continue;
if(box.contains(grappaNexus.rawBounds2D())) {
if(elems == null) {
elems = new Vector();
}
elems.add(edge);
}
}
enm = subg.nodeElements();
Node node;
while(enm.hasMoreElements()) {
node = (Node)enm.nextElement();
if((grappaNexus = node.grappaNexus) == null) continue;
if(box.contains(grappaNexus.rawBounds2D())) {
if(elems == null) {
elems = new Vector();
}
elems.add(node);
}
}
}
return(elems);
}
/**
* Set the highlight on an element and, possibly, related elements.
* Since deletion can affect related elements (i.e., the edges connected
* to a node or the sub-elements of a subgraph), those elements are
* affected as well when highlighting.
*
* @param elem the element whose highlighting is to be adjusted.
* @param mode the highlight mode to apply or remove; a mode of
* zero indicates all highlighting is turned off regardless
* of the setting.
* @param setting one of HIGHLIGHT_ON, HIGHLIGHT_OFF or HIGHLIGHT_TOGGLE.
*/
public static void setHighlight(Element elem, int mode, int setting) {
if(elem == null) return;
if(mode == 0) {
// treat delete specially
boolean wasDelete = ((elem.highlight&DELETION_MASK) == DELETION_MASK);
elem.highlight = 0;
if(wasDelete) {
if(elem.isNode()) {
Enumeration enm = ((Node)elem).edgeElements();
while(enm.hasMoreElements()) {
((Element)(enm.nextElement())).highlight = 0;
}
} else if(elem.isSubgraph()) {
Enumeration enm = ((Subgraph)elem).elements();
while(enm.hasMoreElements()) {
((Element)(enm.nextElement())).highlight = 0;
}
}
}
} else {
mode &= HIGHLIGHT_MASK;
if(setting == HIGHLIGHT_TOGGLE) {
elem.highlight ^= mode;
} else if(setting == HIGHLIGHT_ON) {
elem.highlight |= mode;
} else {
elem.highlight &= ~mode;
}
if((mode&DELETION_MASK) == DELETION_MASK) {
if(elem.isNode()) {
if((elem.highlight&DELETION_MASK) == DELETION_MASK) {
Enumeration enm = ((Node)elem).edgeElements();
while(enm.hasMoreElements()) {
((Element)(enm.nextElement())).highlight |= DELETION_MASK;
}
} else {
Enumeration enm = ((Node)elem).edgeElements();
while(enm.hasMoreElements()) {
((Element)(enm.nextElement())).highlight &= ~DELETION_MASK;
}
}
} else if(elem.isSubgraph()) {
if((elem.highlight&DELETION_MASK) == DELETION_MASK) {
Enumeration enm = ((Subgraph)elem).elements();
while(enm.hasMoreElements()) {
((Element)(enm.nextElement())).highlight |= DELETION_MASK;
}
} else {
Enumeration enm = ((Subgraph)elem).elements();
while(enm.hasMoreElements()) {
((Element)(enm.nextElement())).highlight &= ~DELETION_MASK;
}
}
}
}
}
}
/**
* Filter the supplied graph using the given connector.
* The connector is either a java.lang.Process or a
* java.net.URLConnection.
* As such, it provides an output stream to which the graph can be
* written and an input stream from which the processed graph can be
* read back in (to replace the original graph).
* Such filtering is useful for processing the graph through a layout
* engine such as the dot program.
*
*
Unlike previous versions of Grappa, this version does not try
* to explicitly redraw the graph after filtering is completed.
*
* @param graph the graph to be processed and reset
* @param connector a Process or URLConnector that provides an input and
* output stream
* @return true if the filtering completed successfully, false otherwise.
*/
public static boolean filterGraph(Graph graph, Object connector) {
return filterGraph(graph,connector,null);
}
/**
* Filter the supplied graph using the given connector.
* The connector is either a java.lang.Process or a
* java.net.URLConnection.
* As such, it provides an output stream to which the graph can be
* written and an input stream from which the processed graph can be
* read back in (to replace the original graph).
* Such filtering is useful for processing the graph through a layout
* engine such as the dot program. The existing graph is reset
* and its contents are replaced with the graph that is read in.
*
*
Unlike previous versions of Grappa, this version does not try
* to explicitly redraw the graph after filtering is completed.
*
* @param graph the graph to be processed and reset
* @param connector a Process or URLConnector that provides an input and
* output stream
* @param preamble if not null, a string sent to filter prior to graph
* @return true if the filtering completed successfully, false otherwise.
*/
public static boolean filterGraph(Graph graph, Object connector, String preamble) {
if(connector == null) return false;
OutputStream toFilterRaw = null;
try {
if(connector instanceof java.lang.Process) {
toFilterRaw = ((java.lang.Process)connector).getOutputStream();
} else if(connector instanceof java.net.URLConnection) {
toFilterRaw = ((java.net.URLConnection)connector).getOutputStream();
} else {
return false;
}
} catch(IOException ioex) {
Grappa.displayException(ioex);
return false;
}
BufferedWriter toFilter = new BufferedWriter(new OutputStreamWriter(toFilterRaw));
String content = null;
boolean status = true;
graph.filterMode = true;
try {
StringWriter theGraph = new StringWriter();
graph.printGraph(theGraph);
theGraph.flush();
content = theGraph.toString();
theGraph.close();
} catch(Exception ex) {
Grappa.displayException(ex);
return false;
}
finally {
graph.filterMode = false;
}
try {
if(preamble != null) {
toFilter.write(preamble,0,preamble.length());
toFilter.flush();
}
toFilter.write(content,0,content.length());
toFilter.flush();
toFilter.close();
} catch(Exception ex) {
Grappa.displayException(ex);
return false;
}
InputStream fromFilterRaw = null;
try {
if(connector instanceof java.lang.Process) {
fromFilterRaw = ((java.lang.Process)connector).getInputStream();
} else if(connector instanceof java.net.URLConnection) {
fromFilterRaw = ((java.net.URLConnection)connector).getInputStream();
} else {
return false;
}
} catch(IOException ioex) {
Grappa.displayException(ioex);
return false;
}
BufferedReader fromFilter = new BufferedReader(new InputStreamReader(fromFilterRaw));
StringBuffer newGraph = new StringBuffer(content.length() + 128);
try {
String line = null;
while((line = fromFilter.readLine()) != null) {
newGraph.append(line);
// assume a lone right-brace on a line is the end-of-graph
if(line.equals(“}”) || line.equals(“}\r”)) {
break;
}
/*
* Need to append new-line on the chance that there was a
* backslash-newline (otherwise need to test for a lone
* backslash at the end of the string and remove it…
* cheaper to just append a newline.
*/
newGraph.append(Grappa.NEW_LINE);
}
} catch(Exception ex) {
Grappa.displayException(ex);
status = false;
if(newGraph.length() == 0) {
newGraph.append(content);
content = null;
}
}
try {
fromFilter.close();
} catch(IOException io) {}
Reader fromReader = null;
try {
fromReader = new StringReader(newGraph.toString());
} catch(Exception ex) {
Grappa.displayException(ex);
return false;
}
graph.reset();
Parser program = new Parser(fromReader,graph.getErrorWriter(),graph);
try {
program.parse();
} catch(Exception ex) {
Grappa.displayException(ex);
status = false;
try {
fromReader.close();
fromReader = new StringReader(content);
} catch(Exception ex2) {
Grappa.displayException(ex2);
return false;
}
program = new Parser(fromReader,graph.getErrorWriter(),graph);
try {
program.parse();
} catch(Exception ex2) {
Grappa.displayException(ex2);
return false;
}
}
return status;
}
/**
* Scroll to the viewport containing the specified GrappaPanel so that
* it is centered on the given point. If the point is not contained in
* the subgraph being displayed in the GrappaPanel, no action is taken.
* If the getParent() method applied to the GrappaPanel argument does not
* return a JViewport, an error message is displayed.
*
* @param cpt the point to place at the center of the GrappaPanel viewport
* @param gpanel the GrappaPanel displaying the graph
*
* @return true for a valid request, false otherwise
*
*/
public static boolean centerPanel(Point2D cpt, GrappaPanel gpanel) {
if(cpt == null || gpanel == null)
return false;
if(!gpanel.getSubgraph().getBoundingBox().contains(cpt.getX(), cpt.getY())) {
return false;
}
Object prnt = gpanel.getParent();
if(!(prnt instanceof javax.swing.JViewport)) {
Grappa.displayException(new RuntimeException(“the parent of the supplied GrappaPanel is not a JViewport”));
return false;
}
javax.swing.JViewport vport = (javax.swing.JViewport)prnt;
java.awt.Rectangle b = gpanel.getBounds();
java.awt.Dimension d = vport.getExtentSize();
AffineTransform transform = gpanel.getTransform();
if(transform == null)
return false;
Point2D p = transform.transform(cpt, null);
Rectangle2D r = new Rectangle2D.Double(p.getX() + (double)b.x – ((double)d.width)/2., p.getY() + (double)b.y – ((double)d.height)/2., (double)d.width, (double)d.height);
r = r.createIntersection(b);
vport.scrollRectToVisible(r.getBounds());
return true;
}
}
att/grappa/GrappaSupportPrintf.java
att/grappa/GrappaSupportPrintf.java/*
* This software may only be used by you under license from AT&T Corp.
* (“AT&T”). A copy of AT&T’s Source Code Agreement is available at
* AT&T’s Internet website having the URL:
*
* If you received this software without first entering into a license
* with AT&T, you have an infringing copy of this software and cannot use
* it without violating AT&T’s intellectual property rights.
*/
package att.grappa;
import java.io.*;
import java.util.*;
/**
* A class providing sprintf support.
*
* @version 1.2, 26 May 2005; Copyright 1996 – 2005 by AT&T Corp.
* @author John Mocenigo and Rich Drechsler, Research @ AT&T Labs
*/
public class GrappaSupportPrintf
implements GrappaConstants
{
///////////////////////////////////////////////////////////////////////////
//
// GrappaSupportPrintf
//
///////////////////////////////////////////////////////////////////////////
/**
* The familiar C-language sprintf rendered in Java and extended for
* some Grappa types.
*
* @param args the first element of this array is a string giving the
* format of the returned string, the remaining elements
* are object to be formatted according to the format.
* @return a string giving a formatted representation of the arguments.
*/
public final static String
sprintf(Object args[]) {
PrintfParser cvt;
StringBuffer prtbuf;
char format[];
int flen;
int argn;
int n;
char ch;
boolean flag;
if(!(args[0] instanceof String)) {
throw new RuntimeException(“initial argument must be format String”);
}
argn = 0;
format = ((String)args[argn++]).toCharArray();
flen = format.length;
prtbuf = new StringBuffer(2 * flen);
cvt = new PrintfParser();
for (n = 0; n < flen; ) { if ((ch = format[n++]) == '%') { if ((n = cvt.parse(format, n)) < flen) { switch (ch = format[n++]) { case 'b': if (args.length <= argn) throw new RuntimeException("too few arguments for format"); if (args[argn] instanceof GrappaBox) flag = ((GrappaBox)args[argn]).isDimensioned(); else flag = true; if (args[argn] instanceof java.awt.geom.Rectangle2D) cvt.buildBox(prtbuf, ((java.awt.geom.Rectangle2D)args[argn++]), false, flag); else throw new RuntimeException("argument " + argn + " should be a Rectangle2D"); break; case 'B': if (args.length <= argn) throw new RuntimeException("too few arguments for format"); if (args[argn] instanceof GrappaBox) flag = ((GrappaBox)args[argn]).isDimensioned(); else flag = true; if (args[argn] instanceof java.awt.geom.Rectangle2D) cvt.buildBox(prtbuf, ((java.awt.geom.Rectangle2D)args[argn++]), true, flag); else throw new RuntimeException("argument " + argn + " should be a Rectangle2D"); break; case 'c': if (args.length <= argn) throw new RuntimeException("too few arguments for format"); if (args[argn] instanceof Character) cvt.buildChar(prtbuf, ((Character)args[argn++]).charValue()); else throw new RuntimeException("argument " + argn + " should be a Character"); break; case 'd': if (args.length <= argn) throw new RuntimeException("too few arguments for format"); if (args[argn] instanceof Number) cvt.buildInteger(prtbuf, ((Number)args[argn++]).intValue()); else throw new RuntimeException("argument " + argn + " should be a Number"); break; case 'o': if (args.length <= argn) throw new RuntimeException("too few arguments for format"); if (args[argn] instanceof Character) cvt.buildOctal(prtbuf, ((Character)args[argn++]).charValue()); else if (args[argn] instanceof Number) cvt.buildOctal(prtbuf, ((Number)args[argn++]).intValue()); else throw new RuntimeException("argument " + argn + " should be a Character or Number"); break; case 'p': if (args.length <= argn) throw new RuntimeException("too few arguments for format"); if (args[argn] instanceof java.awt.geom.Point2D) cvt.buildPoint(prtbuf, ((java.awt.geom.Point2D)args[argn++]), false); else if (args[argn] instanceof java.awt.geom.Dimension2D) cvt.buildSize(prtbuf, ((java.awt.geom.Dimension2D)args[argn++]), false); else throw new RuntimeException("argument " + argn + " should be a Point2D"); break; case 'P': if (args.length <= argn) throw new RuntimeException("too few arguments for format"); if (args[argn] instanceof java.awt.geom.Point2D) cvt.buildPoint(prtbuf, ((java.awt.geom.Point2D)args[argn++]), true); else if (args[argn] instanceof java.awt.geom.Dimension2D) cvt.buildSize(prtbuf, ((java.awt.geom.Dimension2D)args[argn++]), true); else throw new RuntimeException("argument " + argn + " should be a Point2D"); break; case 'x': if (args.length <= argn) throw new RuntimeException("too few arguments for format"); if (args[argn] instanceof Character) cvt.buildHex(prtbuf, ((Character)args[argn++]).charValue(), false); else if (args[argn] instanceof Number) cvt.buildHex(prtbuf, ((Number)args[argn++]).intValue(), false); else throw new RuntimeException("argument " + argn + " should be a Character or Number"); break; case 'X': if (args.length <= argn) throw new RuntimeException("too few arguments for format"); if (args[argn] instanceof Character) cvt.buildHex(prtbuf, ((Character)args[argn++]).charValue(), true); else if (args[argn] instanceof Number) cvt.buildHex(prtbuf, ((Number)args[argn++]).intValue(), true); else throw new RuntimeException("argument " + argn + " should be a Character or Number"); break; case 'e': if (args.length <= argn) throw new RuntimeException("too few arguments for format"); if (args[argn] instanceof Character) cvt.buildExp(prtbuf, ((Character)args[argn++]).charValue(), false); else if (args[argn] instanceof Number) cvt.buildExp(prtbuf, ((Number)args[argn++]).doubleValue(), false); else throw new RuntimeException("argument " + argn + " should be a Character or Number"); break; case 'E': if (args.length <= argn) throw new RuntimeException("too few arguments for format"); if (args[argn] instanceof Character) cvt.buildExp(prtbuf, ((Character)args[argn++]).charValue(), true); else if (args[argn] instanceof Number) cvt.buildExp(prtbuf, ((Number)args[argn++]).doubleValue(), true); else throw new RuntimeException("argument " + argn + " should be a Character or Number"); break; case 'f': if (args.length <= argn) throw new RuntimeException("too few arguments for format"); if (args[argn] instanceof Character) cvt.buildFloat(prtbuf, ((Character)args[argn++]).charValue()); else if (args[argn] instanceof Number) cvt.buildFloat(prtbuf, ((Number)args[argn++]).doubleValue()); else throw new RuntimeException("argument " + argn + " should be a Character or Number"); break; case 'g': if (args.length <= argn) throw new RuntimeException("too few arguments for format"); if (args[argn] instanceof Character) cvt.buildFlex(prtbuf, ((Character)args[argn++]).charValue(), false); else if (args[argn] instanceof Number) cvt.buildFlex(prtbuf, ((Number)args[argn++]).doubleValue(), false); else throw new RuntimeException("argument " + argn + " should be a Character or Number"); break; case 'G': if (args.length <= argn) throw new RuntimeException("too few arguments for format"); if (args[argn] instanceof Character) cvt.buildFlex(prtbuf, ((Character)args[argn++]).charValue(), true); else if (args[argn] instanceof Number) cvt.buildFlex(prtbuf, ((Number)args[argn++]).doubleValue(), true); else throw new RuntimeException("argument " + argn + " should be a Character or Number"); break; case 's': if (args.length <= argn) throw new RuntimeException("too few arguments for format"); cvt.buildString(prtbuf, args[argn++].toString()); break; case '%': prtbuf.append('%'); break; default: // different compilers handle this different ways, // some just do the equivalent of prtbuf.append(ch), // but we will just ignore the unrecognized format break; } } else prtbuf.append(ch); } else if (ch == '\\') { if (n < flen) { switch (ch = format[n++]) { case 'b': prtbuf.append('\b'); break; case 'f': prtbuf.append('\f'); break; case 'n': prtbuf.append('\n'); break; case 'r': prtbuf.append('\r'); break; case 't': prtbuf.append('\t'); break; case 'u': if ((n+3) < flen) { if ( GrappaSupport.isdigit(format[n]) && GrappaSupport.isdigit(format[n+1]) && GrappaSupport.isdigit(format[n+2]) && GrappaSupport.isdigit(format[n+3]) ) { int uni = (int)format[n+3]+16*(int)format[n+2]+256*(int)format[n+1]+4096*(int)format[n]; prtbuf.append((char)uni); n += 4; } else prtbuf.append('u'); } else prtbuf.append('u'); break; case '"': prtbuf.append('\"'); break; case '\'': prtbuf.append('\''); break; case '\\': prtbuf.append('\\'); break; case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': // need to fix this, assumes 3 digit octals if ((n+1) < flen) { if ( GrappaSupport.isdigit(format[n]) && GrappaSupport.isdigit(format[n+1]) ) { int oct = (int)format[n+1]+8*(int)format[n]+64*(int)ch; prtbuf.append((char)oct); n += 2; } else prtbuf.append(ch); } else prtbuf.append(ch); break; } } else prtbuf.append(ch); } else prtbuf.append(ch); } return(prtbuf.toString()); } /////////////////////////////////////////////////////////////////////////// } class PrintfParser implements GrappaConstants { private boolean alternate; private boolean rightpad; private boolean sign; private boolean space; private boolean zeropad; private boolean trim; private int precision; private int width; private String plus; private char padding; private StringBuffer scratch; /////////////////////////////////////////////////////////////////////////// // // Constructor // /////////////////////////////////////////////////////////////////////////// PrintfParser() { scratch = new StringBuffer(); } /////////////////////////////////////////////////////////////////////////// // // printfParser // /////////////////////////////////////////////////////////////////////////// final int parse(char cfmt[]) { return(parse(cfmt, 0)); } /////////////////////////////////////////////////////////////////////////// final int parse(char cfmt[], int n) { boolean done; int ch; // // Parse the conversion specification that starts at index n // in fmt. Results are stored in the class variables and the // position of the character that stopped the parse is // returned to the caller. // alternate = false; rightpad = false; sign = false; space = false; zeropad = false; trim = false; for (done = false; n < cfmt.length && !done; n++) { switch (cfmt[n]) { case '-': rightpad = true; break; case '+': sign = true; break; case ' ': space = true; break; case '0': zeropad = true; break; case '#': alternate = true; break; default: done = true; n--; break; } } plus = (sign ? "+" : (space ? " " : "")); for (width = 0; n < cfmt.length && GrappaSupport.isdigit(ch = cfmt[n]); n++) width = width*10 + (ch - '0'); if (n < cfmt.length && cfmt[n] == '.') { n++; for (precision = 0; n < cfmt.length && GrappaSupport.isdigit(ch = cfmt[n]); n++) precision = precision*10 + (ch - '0'); } else precision = -1; padding = (zeropad && !rightpad) ? '0' : ' '; return(n); } /////////////////////////////////////////////////////////////////////////// final StringBuffer buildChar(StringBuffer buf, int arg) { scratch.setLength(0); scratch.append((char)arg); return(strpad(buf, scratch.toString(), ' ', width, rightpad)); } /////////////////////////////////////////////////////////////////////////// final StringBuffer buildExp(StringBuffer buf, double arg, boolean upper) { double exp; double base; double val; int sign; precision = (precision >= 0) ? precision : 6;
val = arg;
sign = (val >= 0) ? 1 : -1;
val = (val < 0) ? -val : val;
if (val >= 1) {
exp = Math.log(val)/LOG10;
base = Math.pow(10, exp – (int)exp);
} else {
exp = Math.log(val/10)/LOG10;
base = Math.pow(10, exp – (int)exp + 1);
}
scratch.setLength(0);
scratch.append(upper ? “E” : “e”);
scratch.append(exp > 0 ? ‘+’ : ‘-‘);
strpad(scratch, (“” + (int)(exp > 0 ? exp : -exp)), ‘0’, 2, false);
if (padding == ‘0’ && precision >= 0)
padding = ‘ ‘;
return(strpad(buf, doubleToString(sign*base, scratch.toString()), padding, width, rightpad));
}
///////////////////////////////////////////////////////////////////////////
final StringBuffer
buildFlex(StringBuffer buf, double arg, boolean upper) {
double exp;
double val;
double ival;
StringBuffer retbuf;
int iexp;
int pr;
trim = true;
val = arg;
ival = (int)arg;
val = (val < 0) ? -val : val;
if (val >= 1) {
exp = Math.log(val)/LOG10;
} else {
exp = Math.log(val/10)/LOG10;
}
iexp = (int)exp;
precision = (precision >= 0) ? –precision : 5;
if (val == ival) {
if (alternate) {
if (precision < 0 || iexp <= precision) {
precision -= iexp;
retbuf = buildFloat(buf, arg);
} else retbuf = buildExp(buf, arg, upper);
} else {
if (precision < 0 || iexp <= precision) {
precision = -1;
retbuf = buildInteger(buf, (int)arg);
} else retbuf = buildExp(buf, arg, upper);
}
} else if (iexp < -4 || iexp > precision)
retbuf = buildExp(buf, arg, upper);
else retbuf = buildFloat(buf, arg);
return(retbuf);
}
///////////////////////////////////////////////////////////////////////////
final StringBuffer
buildPoint(StringBuffer buf, java.awt.geom.Point2D parg, boolean upper) {
double[] arg = { 0, 0 };
double[] exp = { 0, 0 };
double[] val = { 0, 0 };
double[] ival = { 0, 0 };
int[] iexp = { 0, 0 };
StringBuffer retbuf = null;
int orig_precision;
int pr;
trim = true;
arg[0] = parg.getX();
arg[1] = (Grappa.negateStringYCoord?-parg.getY():parg.getY());
val[0] = arg[0];
val[1] = arg[1];
orig_precision = precision;
for(int i=0; i<2; i++) {
precision = orig_precision;
ival[i] = (int)val[i];
val[i] = (val[i] < 0) ? -val[i] : val[i];
if (val[i] >= 1) {
exp[i] = Math.log(val[i])/LOG10;
} else {
exp[i] = Math.log(val[i]/10)/LOG10;
}
iexp[i] = (int)exp[i];
precision = (precision >= 0) ? –precision : 5;
if (val[i] == ival[i]) {
if (alternate) {
if (precision < 0 || iexp[i] <= precision) {
precision -= iexp[i];
retbuf = buildFloat(buf, arg[i]);
} else retbuf = buildExp(buf, arg[i], upper);
} else {
if (precision < 0 || iexp[i] <= precision) {
precision = -1;
retbuf = buildInteger(buf, (long)arg[i]);
} else retbuf = buildExp(buf, arg[i], upper);
}
} else if (iexp[i] < -4 || iexp[i] > precision)
retbuf = buildExp(buf, arg[i], upper);
else retbuf = buildFloat(buf, arg[i]);
if(i == 0) {
retbuf = retbuf.append(‘,’);
buf = retbuf;
}
}
return(retbuf);
}
///////////////////////////////////////////////////////////////////////////
final StringBuffer
buildSize(StringBuffer buf, java.awt.geom.Dimension2D parg, boolean upper) {
double[] arg = { 0, 0 };
double[] exp = { 0, 0 };
double[] val = { 0, 0 };
double[] ival = { 0, 0 };
int[] iexp = { 0, 0 };
StringBuffer retbuf = null;
int orig_precision;
int pr;
trim = true;
arg[0] = parg.getWidth();
arg[1] = parg.getHeight();
val[0] = arg[0];
val[1] = arg[1];
orig_precision = precision;
for(int i=0; i<2; i++) {
precision = orig_precision;
ival[i] = (int)val[i];
val[i] = (val[i] < 0) ? -val[i] : val[i];
if (val[i] >= 1) {
exp[i] = Math.log(val[i])/LOG10;
} else {
exp[i] = Math.log(val[i]/10)/LOG10;
}
iexp[i] = (int)exp[i];
precision = (precision >= 0) ? –precision : 5;
if (val[i] == ival[i]) {
if (alternate) {
if (precision < 0 || iexp[i] <= precision) {
precision -= iexp[i];
retbuf = buildFloat(buf, arg[i]);
} else retbuf = buildExp(buf, arg[i], upper);
} else {
if (precision < 0 || iexp[i] <= precision) {
precision = -1;
retbuf = buildInteger(buf, (long)arg[i]);
} else retbuf = buildExp(buf, arg[i], upper);
}
} else if (iexp[i] < -4 || iexp[i] > precision)
retbuf = buildExp(buf, arg[i], upper);
else retbuf = buildFloat(buf, arg[i]);
if(i == 0) {
retbuf = retbuf.append(‘,’);
buf = retbuf;
}
}
return(retbuf);
}
///////////////////////////////////////////////////////////////////////////
final StringBuffer
buildBox(StringBuffer buf, java.awt.geom.Rectangle2D parg, boolean upper, boolean dimensioned) {
double[] arg = { 0, 0, 0, 0 };
double[] exp = { 0, 0, 0, 0 };
double[] val = { 0, 0, 0, 0 };
double[] ival = { 0, 0, 0, 0 };
int[] iexp = { 0, 0, 0, 0 };
StringBuffer retbuf = null;
int orig_precision;
int pr;
trim = true;
if(!dimensioned) {
arg[0] = parg.getX();
arg[1] = parg.getY();
arg[2] = arg[0] + arg[2];
arg[3] = arg[1] + arg[3];
arg[1] = (Grappa.negateStringYCoord?-arg[1]:arg[1]);
arg[3] = (Grappa.negateStringYCoord?-arg[3]:arg[3]);
} else {
arg[0] = parg.getX();
arg[1] = (Grappa.negateStringYCoord?-parg.getY():parg.getY());
arg[2] = parg.getWidth();
arg[3] = parg.getHeight();
}
val[0] = arg[0];
val[1] = arg[1];
val[2] = arg[2];
val[3] = arg[3];
orig_precision = precision;
for(int i=0; i<4; i++) {
precision = orig_precision;
ival[i] = (int)val[i];
val[i] = (val[i] < 0) ? -val[i] : val[i];
if (val[i] >= 1) {
exp[i] = Math.log(val[i])/LOG10;
} else {
exp[i] = Math.log(val[i]/10)/LOG10;
}
iexp[i] = (int)exp[i];
precision = (precision >= 0) ? –precision : 5;
if (val[i] == ival[i]) {
if (alternate) {
if (precision < 0 || iexp[i] <= precision) {
precision -= iexp[i];
retbuf = buildFloat(buf, arg[i]);
} else retbuf = buildExp(buf, arg[i], upper);
} else {
if (precision < 0 || iexp[i] <= precision) {
precision = -1;
retbuf = buildInteger(buf, (long)arg[i]);
} else retbuf = buildExp(buf, arg[i], upper);
}
} else if (iexp[i] < -4 || iexp[i] > precision)
retbuf = buildExp(buf, arg[i], upper);
else retbuf = buildFloat(buf, arg[i]);
if(i < 3) {
retbuf = retbuf.append(',');
buf = retbuf;
}
}
return(retbuf);
}
///////////////////////////////////////////////////////////////////////////
final StringBuffer
buildFloat(StringBuffer buf, double arg) {
double val;
int sign;
precision = (precision >= 0) ? precision : 6;
val = arg;
if (padding == ‘0’ && precision >= 0)
padding = ‘ ‘;
return(strpad(buf, doubleToString(val, “”), padding, width, rightpad));
}
///////////////////////////////////////////////////////////////////////////
final StringBuffer
buildHex(StringBuffer buf, int arg, boolean upper) {
String str;
scratch.setLength(0);
str = (upper) ? Integer.toHexString(arg).toUpperCase() : Integer.toHexString(arg);
if (precision > str.length()) {
if (alternate)
scratch.append(upper ? “0X” : “0x”);
strpad(scratch, str, ‘0’, precision, false);
strpad(buf, scratch.toString(), ‘ ‘, width, rightpad);
} else {
if (zeropad && !rightpad && precision < 0) {
if (alternate) {
if (width > 2) {
strpad(scratch, str, ‘0’, width-2, rightpad);
buf.append(upper ? “0X” : “0x”);
buf.append(scratch.toString());
} else {
buf.append(upper ? “0X” : “0x”);
buf.append(str);
}
} else strpad(buf, str, ‘0’, width, rightpad);
} else {
if (alternate) {
scratch.append(upper ? “0X” : “0x”);
scratch.append(str);
str = scratch.toString();
}
strpad(buf, str, ‘ ‘, width, rightpad);
}
}
return(buf);
}
///////////////////////////////////////////////////////////////////////////
final StringBuffer
buildInteger(StringBuffer buf, long arg) {
String str;
String sign;
long val;
scratch.setLength(0);
val = arg;
sign = (val >= 0) ? plus : “-“;
str = “” + ((val < 0) ? -val : val);
if (precision > str.length()) {
strpad(scratch, str, ‘0’, precision, false);
scratch.insert(0, sign);
} else {
scratch.append(sign);
scratch.append(str);
}
if (padding == ‘0’ && precision >= 0)
padding = ‘ ‘;
return(strpad(buf, scratch.toString(), padding, width, rightpad));
}
///////////////////////////////////////////////////////////////////////////
final StringBuffer
buildOctal(StringBuffer buf, int arg) {
String str;
scratch.setLength(0);
if (alternate)
scratch.append(‘0’);
scratch.append(Integer.toOctalString(arg));
if (precision > scratch.length()) {
str = scratch.toString();
scratch.setLength(0);
strpad(scratch, str, ‘0’, precision, false);
}
if (padding == ‘0’ && precision >= 0)
padding = ‘ ‘;
return(strpad(buf, scratch.toString(), padding, width, rightpad));
}
///////////////////////////////////////////////////////////////////////////
final StringBuffer
buildString(StringBuffer buf, String arg) {
String str;
if (precision > 0) {
if (precision < arg.length())
str = arg.substring(0, precision);
else str = arg;
} else str = arg;
return(strpad(buf, str, padding, width, rightpad));
}
///////////////////////////////////////////////////////////////////////////
//
// Private methods
//
///////////////////////////////////////////////////////////////////////////
private String
doubleToString(double val, String exp) {
String sign;
double whole;
double power;
double frac;
//
// Building the resulting String up by casting to an int or long
// doesn't always work, so we use algorithm that may look harder
// and slower than necessary.
//
scratch.setLength(0);
sign = (val >= 0) ? plus : “-“;
val = (val < 0) ? -val : val;
whole = Math.floor(val);
if (precision != 0) {
power = Math.pow(10, precision);
frac = (val - whole)*power;
scratch.append((long)whole);
String tail = (""+((long)Math.round(frac)));
if(trim) {
int len = tail.length();
int extra = 0;
while(extra < len && tail.charAt(len-extra-1) == '0') extra++;
if(extra == len) {
if(exp.length() > 0) {
tail = “.0”;
} else {
tail = “”;
}
precision = 0;
} else if(extra > 0) {
scratch.append(‘.’);
tail = tail.substring(0,len-extra);
precision -= extra;
} else {
scratch.append(‘.’);
}
} else {
scratch.append(‘.’);
}
if (precision > 0 && (power/10) > frac) {
strpad(scratch, tail, ‘0’, precision, false);
} else scratch.append(tail);
scratch.append(exp);
} else {
scratch.append((long)whole);
if (alternate && exp.length() == 0)
scratch.append(‘.’);
scratch.append(exp);
}
if (zeropad && !rightpad) {
String str = scratch.toString();
scratch.setLength(0);
strpad(scratch, str, ‘0’, width – sign.length(), false);
}
scratch.insert(0, sign);
return(scratch.toString());
}
///////////////////////////////////////////////////////////////////////////
private StringBuffer
strpad(StringBuffer buf, String str, int ch, int width, boolean right) {
int len;
int n;
if (width > 0) {
if ((len = width – str.length()) > 0) {
if (right)
buf.append(str);
for (n = 0; n < len; n++)
buf.append((char)ch);
if (!right)
buf.append(str);
} else buf.append(str);
} else buf.append(str);
return(buf);
}
///////////////////////////////////////////////////////////////////////////
}
att/grappa/GrappaSupportRects.java
att/grappa/GrappaSupportRects.java
/*
* This software may only be used by you under license from AT&T Corp.
* ("AT&T"). A copy of AT&T's Source Code Agreement is available at
* AT&T's Internet website having the URL:
*
* If you received this software without first entering into a license
* with AT&T, you have an infringing copy of this software and cannot use
* it without violating AT&T’s intellectual property rights.
*/
package att.grappa;
import java.awt.*;
import java.awt.geom.*;
import java.util.*;
/**
* This class provides a method for parsing RECORD_SHAPE node
* labels and deriving the RECT_ATTR information from it. It
* is called by the GrappaNexus class.
*
* @version 1.2, 26 May 2005; Copyright 1996 – 2005 by AT&T Corp.
* @author John Mocenigo, Research @ AT&T Labs
* @see Graph
*/
public class GrappaSupportRects
implements GrappaConstants
{
/**
* Rough font sizing information for the roman (or serif) font.
*/
final static double[] romanFontwidth = { // +——+
0.2500, 0.3330, 0.4080, 0.5000, 0.5000, 0.8330, // | !”#$%|
0.7780, 0.3330, 0.3330, 0.3330, 0.5000, 0.5640, // |&'()*+|
0.2500, 0.3330, 0.2500, 0.2780, 0.5000, 0.5000, // |,-./01|
0.5000, 0.5000, 0.5000, 0.5000, 0.5000, 0.5000, // |234567|
0.5000, 0.5000, 0.2780, 0.2780, 0.5640, 0.5640, // |89:;<=|
0.5640, 0.4440, 0.9210, 0.7220, 0.6670, 0.6670, // |>?@ABC|
0.7220, 0.6110, 0.5560, 0.7220, 0.5560, 0.3330, // |DEFGHI|
0.3890, 0.7220, 0.6110, 0.8890, 0.7220, 0.7220, // |JKLMNO|
0.5560, 0.7220, 0.6670, 0.5560, 0.6110, 0.7220, // |PQRSTU|
0.7220, 0.9440, 0.7220, 0.7220, 0.6110, 0.3330, // |VWXYZ[|
0.2780, 0.3330, 0.4690, 0.5000, 0.3330, 0.4440, // |\]^_`a|
0.5000, 0.4440, 0.5000, 0.4440, 0.3330, 0.5000, // |bcdefg|
0.3330, 0.2780, 0.2780, 0.5000, 0.2780, 0.7780, // |hijklm|
0.5000, 0.5000, 0.5000, 0.5000, 0.3330, 0.3890, // |nopqrs|
0.2780, 0.5000, 0.5000, 0.7220, 0.5000, 0.5000, // |tuvwxy|
0.4440, 0.4800, 0.2000, 0.4800, 0.5410, 0.0 // |z{|}~/
}; // +—–+
/**
* Rough font sizing information for the helvetica (or sansserif) font.
*/
final static double[] helveticaFontwidth = { // +——+
0.2780, 0.2780, 0.3550, 0.5560, 0.5560, 0.8890, // | !”#$%|
0.6670, 0.2210, 0.3330, 0.3330, 0.3890, 0.5840, // |&'()*+|
0.2780, 0.3330, 0.2780, 0.2780, 0.5560, 0.5560, // |,-./01|
0.5560, 0.5560, 0.5560, 0.5560, 0.5560, 0.5560, // |234567|
0.5560, 0.5560, 0.2780, 0.2780, 0.5840, 0.5840, // |89:;<=|
0.5840, 0.5560, 01.015, 0.6670, 0.6670, 0.7220, // |>?@ABC|
0.7220, 0.6670, 0.6110, 0.7780, 0.6110, 0.2780, // |DEFGHI|
0.5000, 0.6670, 0.5560, 0.8330, 0.7220, 0.7780, // |JKLMNO|
0.6670, 0.7780, 0.7220, 0.6670, 0.6110, 0.7220, // |PQRSTU|
0.6670, 0.9440, 0.6670, 0.6670, 0.6110, 0.2780, // |VWXYZ[|
0.2780, 0.2780, 0.4690, 0.5560, 0.2220, 0.5560, // |\]^_`a|
0.5560, 0.5000, 0.5560, 0.5560, 0.2780, 0.5560, // |bcdefg|
0.2780, 0.2220, 0.2220, 0.5000, 0.2220, 0.8330, // |hijklm|
0.5560, 0.5560, 0.5560, 0.5560, 0.3330, 0.5000, // |nopqrs|
0.2780, 0.5560, 0.5000, 0.7220, 0.5000, 0.5000, // |tuvwxy|
0.5000, 0.3340, 0.2600, 0.3340, 0.5840, 0.0 , // |z{|}~/
}; // +—–+
/**
* Rough font sizing information for the courier (or constant) font.
*/
final static double constantFontwidth = 0.6206;
final static int HASTEXT = 1;
final static int HASPORT = 2;
final static int HASTABLE = 4;
final static int INTEXT = 8;
final static int INPORT = 16;
final static char NBSP = ‘\u00a0’; // Unicode no-break space
private static char[] parseArray = null;
private static int arrayOffset = 0;
private static int fields = 0;
private static StringBuffer rbuf = null;
// assumes shape type is RECORD_SHAPE or MRECORD_SHAPE
protected static synchronized Object[] parseRecordInfo(Node node) {
Object[] objs = { null, null, null };
if(node == null) {
return objs;
}
String label = (String)node.getAttributeValue(LABEL_ATTR);
if(label != null && label.equals(“\\N”)) {
label = node.getName();
}
if(label == null || label.length() == 0 || label.indexOf(‘|’) < 0) {
node.setAttribute(RECTS_ATTR, null);
return objs;
}
parseArray = label.toCharArray();
arrayOffset = 0;
TableField tableField = doParse(node, !node.getSubgraph().isLR(), true);
if(tableField == null) {
node.setAttribute(RECTS_ATTR, null);
return objs;
}
tableField.sizeFields();
double width = ((Double)node.getAttributeValue(WIDTH_ATTR)).doubleValue() * PointsPerInch;
double height = ((Double)node.getAttributeValue(HEIGHT_ATTR)).doubleValue() * PointsPerInch;
Dimension sz = new Dimension((int)Math.round(width),(int)Math.round(height));
tableField.resizeFields(sz);
GrappaPoint pos = (GrappaPoint)node.getAttributeValue(POS_ATTR);
tableField.positionFields(new Point((int)Math.round(pos.getX()-width/2.0),(int)Math.round(pos.getY()-height/2.0)));
objs[0] = new String[fields];
objs[1] = new GrappaPoint[fields];
fields = 0;
if(emitFields(tableField,objs)) {
objs[2] = rbuf.toString();
node.setAttribute(RECTS_ATTR, ((String)objs[2]));
} else {
objs = null;
}
rbuf = null;
//for(int i = 0; i < fields; i++) {
//pos = ((GrappaPoint[])objs[1])[i];
//pos.setLocation(pos.getX() - width, pos.getY() - height);
//}
return objs;
}
private static boolean emitFields(TableField tf, Object[] objs) {
boolean retval = false;
if(tf == null) return false;
int fc = tf.fieldCount();
if(fc == 0) {
Rectangle rect = tf.getBounds();
if(rbuf == null) {
rbuf = new StringBuffer();
} else {
rbuf.append(' ');
}
rbuf.append(rect.x);
rbuf.append(',');
rbuf.append(Grappa.negateStringYCoord?-rect.y:rect.y);
rbuf.append(',');
rbuf.append(rect.x+rect.width);
rbuf.append(',');
rbuf.append(Grappa.negateStringYCoord?(-rect.y-rect.height):(rect.y+rect.height));;
((String[])objs[0])[fields] = tf.getText();
((GrappaPoint[])objs[1])[fields] = new GrappaPoint(rect.getCenterX(), rect.getCenterY());
fields++;
return true;
}
for(int cnt = 0; cnt < fc; cnt++) {
if(emitFields(tf.fieldAt(cnt),objs))
retval = true;
}
return(retval);
}
private static TableField doParse(Node node, boolean LR, boolean topLevel) {
int maxf = 1;
int cnt = 0;
for(int pos = arrayOffset; pos < parseArray.length; pos++) {
if(parseArray[pos] == '\\') {
pos++;
if(pos < parseArray.length && (parseArray[pos] == '{' || parseArray[pos] == '}' || parseArray[pos] == '|')) {
continue;
}
}
if(parseArray[pos] == '{') {
cnt++;
} else if(parseArray[pos] == '}') {
cnt--;
} else if(cnt == 0 && parseArray[pos] == '|') {
maxf++;
}
if(cnt < 0) {
break;
}
}
TableField rv = new TableField();
rv.setLR(LR);
rv.subfields(maxf);
if(topLevel) {
rv.setParent(null);
}
StringBuffer textBuf, portBuf;
textBuf = new StringBuffer();
portBuf = new StringBuffer();
int mode = 0;
int fi = 0;
boolean wflag = true;
TableField tf = null;
char curCh = '\000';
while(wflag) {
if(arrayOffset >= parseArray.length) {
curCh = ‘\000’;
wflag = false;
} else {
curCh = parseArray[arrayOffset];
}
switch((int)curCh) {
case ‘<':
if((mode & (HASTABLE|HASPORT)) != 0) {
return null;
}
mode |= (HASPORT|INPORT);
arrayOffset++;
break;
case '>‘:
if((mode & INPORT) == 0) {
return null;
}
mode &= ~INPORT;
arrayOffset++;
break;
case ‘{‘:
arrayOffset++;
if(mode != 0 || arrayOffset >= parseArray.length) {
return null;
}
mode = HASTABLE;
if((tf = doParse(node,!LR,false)) == null) {
return null;
} else {
rv.addField(tf);
tf.setParent(rv);
}
break;
case ‘}’:
case ‘|’:
case ‘\000’:
if((arrayOffset >= parseArray.length && !topLevel) || (mode&INPORT) != 0) {
return null;
}
if((mode&HASTABLE) == 0) {
tf = new TableField();
rv.addField(tf);
tf.setLR(!LR);
tf.setParent(rv);
if((mode&HASPORT) != 0) {
tf.setId(portBuf.toString().trim());
portBuf.setLength(0);
}
}
if((mode&(HASTEXT|HASTABLE)) == 0) {
mode |= HASTEXT;
textBuf.append(‘ ‘);
}
if((mode&HASTEXT) != 0) {
tf.setTextBounds(textBuf.toString().trim(),node);
fields++;
//tf.setLR(true);
textBuf.setLength(0);
}
if(arrayOffset < parseArray.length) {
if(curCh == '}') {
arrayOffset++;
return rv;
}
mode = 0;
arrayOffset++;
}
break;
case '\\':
if(arrayOffset+1 < parseArray.length) {
if(isSpec(parseArray[arrayOffset+1])) {
arrayOffset++;
curCh = parseArray[arrayOffset];
} else if(parseArray[arrayOffset+1] == ' ') {
arrayOffset++;
curCh = NBSP;
}
}
// fall through...
default:
if((mode&HASTABLE) != 0 && curCh != ' ' && curCh != NBSP) {
return null;
}
if((mode&(INTEXT|INPORT)) == 0 && curCh != ' ' && curCh != NBSP) {
mode |= (INTEXT|HASTEXT);
}
if((mode&INTEXT) != 0) {
textBuf.append(curCh);
} else if((mode&INPORT) != 0) {
portBuf.append(curCh);
}
arrayOffset++;
break;
}
}
return rv;
}
private static boolean isSpec(char c) {
return ((c) == '{' || (c) == '}' || (c) == '|' || (c) == '<' || (c) == '>‘);
}
}
class TableField
implements GrappaConstants
{
private Dimension size = new Dimension();
private Rectangle bounds = new Rectangle();
private Rectangle textBounds = null;
private TableField[] subFields = null;
private int subFieldsUsed = 0;
private boolean orientLR = false;
private String idTag = null;
private String text = null;
private TableField parent = null;
/**
* Creates an empty TableField
instance.
*/
TableField() {
//super();
}
void setParent(TableField prnt) {
parent = prnt;
}
TableField getTopMost() {
TableField topper = this;
while(topper.getParent() != null)
topper = topper.getParent();
return topper;
}
TableField getParent() {
return parent;
}
String getText() {
return text;
}
String getIdentifier() {
StringBuffer buf = new StringBuffer();
if(isLR()) {
buf.append(“LR:”);
} else {
buf.append(“TB:”);
}
buf.append(fieldCount());
buf.append(‘(‘);
buf.append(text);
buf.append(‘)’);
TableField prnt = getParent();
while(prnt != null) {
buf.append(‘,’);
buf.append(prnt.fieldCount());
buf.append(‘(‘);
buf.append(prnt.getText());
buf.append(‘)’);
prnt = prnt.getParent();
}
return buf.toString();
}
/**
* Get the bounding box of this element
*
* @return the bounding box of this element
*/
Rectangle getBounds() {
return bounds;
}
void setBounds(int x, int y, int width, int height) {
bounds.setBounds(x,y,width,height);
}
void setBounds(Rectangle r) {
bounds.setBounds(r);
}
/**
* Get the size of this object.
*
* @return the size of this object.
*/
Dimension getSize() {
return size;
}
void setSize(int width, int height) {
size.setSize(width,height);
}
void setSize(Dimension d) {
size.setSize(d.width,d.height);
}
boolean hasFields() {
if(subFields == null || subFields.length == 0 || subFieldsUsed == 0) {
return false;
}
return true;
}
synchronized int subfields(int len) {
if(len < 1) return 0;
subFields = new TableField[len];
return subFields.length;
}
int fieldCount() {
if(subFields == null) {
return 0;
}
return subFieldsUsed;
}
synchronized void addField(TableField tf) {
// can cause exception
subFields[subFieldsUsed++] = tf;
}
TableField fieldAt(int nbr) {
if(nbr < 0 || nbr >= subFieldsUsed) return null;
return subFields[nbr];
}
boolean isLR() {
return orientLR;
}
void setLR(boolean lr) {
orientLR = lr;
}
String getId() {
return idTag;
}
void setId(String id) {
idTag = null;
if(id == null) return;
char[] array = id.toCharArray();
boolean hadNBSP = false;
for(int i = 0; i < array.length; i++) {
if(array[i] == GrappaSupportRects.NBSP) {
array[i] = ' ';
hadNBSP = true;
}
}
if(hadNBSP) idTag = new String(array,0,array.length);
else idTag = id;
}
Dimension sizeFields() {
return sizeUpFields(this);
}
private Dimension sizeUpFields(TableField tf) {
//System.err.println(tf.getIdentifier());
int fc = tf.fieldCount();
if(fc == 0) {
if(tf.getTextBounds() != null) {
tf.setSize(tf.getTextBounds().getSize());
} else {
tf.setSize(0,0);
}
} else {
Dimension dtmp = null;
Dimension dim = new Dimension();
for(int cnt = 0; cnt < fc; cnt++) {
dtmp = sizeUpFields(tf.fieldAt(cnt));
if(tf.isLR()) {
dim.width += dtmp.width;
dim.height = (dim.height > dtmp.height) ? dim.height : dtmp.height;
} else {
dim.width = (dim.width > dtmp.width) ? dim.width : dtmp.width;
dim.height += dtmp.height;
}
}
tf.setSize(dim);
}
//System.err.println(“Size:”+tf.getSize()+”;”+tf.getIdentifier());
return tf.getSize();
}
Dimension resizeFields(Dimension sz) {
resizeUpFields(this,sz);
return this.getSize();
}
void resizeUpFields(TableField tf, Dimension sz) {
//System.err.println(tf.getIdentifier());
Dimension delta = new Dimension(sz.width – tf.getSize().width, sz.height – tf.getSize().height);
tf.setSize(sz);
int fc = tf.fieldCount();
if(fc == 0) {
//System.err.println(“Size:”+tf.getSize()+”;”+tf.getIdentifier());
return;
}
// adjust children, if any
double incr = 0;
if(tf.isLR()) {
incr = (double)delta.width / (double)fc;
} else {
incr = (double)delta.height / (double)fc;
}
TableField tfield = null;
int amt = 0;
// reuse old space under new name for readability
Dimension newSz = delta;
for(int cnt = 0; cnt < fc; cnt++) {
tfield = tf.fieldAt(cnt);
amt = (int)Math.floor(((double)(cnt+1))*incr) - (int)Math.floor(((double)cnt)*incr);
if(tf.isLR()) {
newSz.setSize(tfield.getSize().width+amt,sz.height);
} else {
newSz.setSize(sz.width,tfield.getSize().height+amt);
}
resizeUpFields(tfield,newSz);
}
}
void positionFields(Point pos) {
posFields(this,pos);
}
private void posFields(TableField tf, Point pos) {
tf.setBounds(pos.x,pos.y,tf.getSize().width,tf.getSize().height);
// clip spillage outside outer-most bounds
Rectangle b1 = tf.getBounds();
Rectangle b2 = tf.getTopMost().getBounds();
int tmpi;
tmpi = Math.max(b1.x,b2.x);
b1.width = Math.min(b1.x+b1.width,b2.x+b2.width) - tmpi;
b1.x = tmpi;
tmpi = Math.max(b1.y,b2.y);
b1.height = Math.min(b1.y+b1.height,b2.y+b2.height) - tmpi;
b1.y = tmpi;
int fc = tf.fieldCount();
if(fc == 0) {
return;
}
TableField tfield = null;
for(int cnt = 0; cnt < fc; cnt++) {
tfield = tf.fieldAt(cnt);
posFields(tfield,new Point(pos));
if(tf.isLR()) {
pos.x += tfield.getSize().width;
} else {
pos.y += tfield.getSize().height;
}
}
}
void setTextBounds(String str, Node node) {
int lines = 1;
boolean cwFont = false;
double[] fontwidth = { GrappaSupportRects.constantFontwidth };
String fontname = node.getAttribute(FONTNAME_ATTR).getStringValue().toLowerCase();
if(fontname.startsWith("courier") || fontname.startsWith("monospaced")) {
cwFont = true;
} else if(fontname.startsWith("helvetica") || fontname.startsWith("sansserif")) {
fontwidth = GrappaSupportRects.helveticaFontwidth;
} else {
fontwidth = GrappaSupportRects.romanFontwidth;
}
char[] array = str.toCharArray();
double fwidth = 0;
double xwidth = 0;
int value = 0;
for(int i = 0; i < array.length; i++) {
if(array[i] == GrappaSupportRects.NBSP) {
array[i] = ' ';
}
if(array[i] == '\\' && (i+1) < array.length) {
if(array[i+1] == 'n' || array[i+1] == 'l' || array[i+1] == 'r') {
lines++;
i++;
if(fwidth > xwidth)
xwidth = fwidth;
fwidth = 0;
continue;
}
}
value = array[i] – 32;
fwidth += (cwFont) ? fontwidth[0] : ((value >= 0 && value < fontwidth.length) ? fontwidth[value] : 0 );
}
if(fwidth > xwidth)
xwidth = fwidth;
int height = ((Integer)node.getAttributeValue(FONTSIZE_ATTR)).intValue();
int width = (int)Math.round((double)height * xwidth);
textBounds = new Rectangle(0,0,width,height*lines);
text = str;
}
Rectangle getTextBounds() {
return(textBounds);
}
void debugID() {
int fc = fieldCount();
if(fc == 0) {
return;
}
TableField tfield = null;
for(int cnt = 0; cnt < fc; cnt++) {
tfield = fieldAt(cnt);
tfield.debugID();
}
}
}
att/grappa/Lexer.java
att/grappa/Lexer.java/*
* This software may only be used by you under license from AT&T Corp.
* ("AT&T"). A copy of AT&T's Source Code Agreement is available at
* AT&T's Internet website having the URL:
*
* If you received this software without first entering into a license
* with AT&T, you have an infringing copy of this software and cannot use
* it without violating AT&T’s intellectual property rights.
*/
package att.grappa;
import java_cup.runtime.Symbol;
import java.util.Hashtable;
import java.io.*;
/**
* A class for doing lexical analysis of dot formatted input.
*
* @version 1.2, 26 May 2005; Copyright 1996 – 2005 by AT&T Corp.
* @author John Mocenigo, Research @ AT&T Labs
*/
public class Lexer
{
/**
* First character of lookahead.
* Set to ‘\n’ initially (needed for initial 2 calls to advance())
*/
private int next_char = ‘\n’;
/**
* Second character of lookahead.
* Set to ‘\n’ initially (needed for initial 2 calls to advance())
*/
private int next_char2 = ‘\n’;
/**
* Current line number for use in error messages.
* Set to -1 to account for next_char/next_char2 initialization
*/
private int current_line = -1;
/**
* Character position in current line.
*/
private int current_position = 1;
/**
* EOF constant.
*/
private static final int EOF_CHAR = -1;
/**
* needed to handle anonymous subgraphs since parser has no precedence
*/
private boolean haveId = false;
/**
* needed for retreating
*/
private int old_char;
private int old_position;
boolean retreated = false;
/**
* Count of total errors detected so far.
*/
private int error_count = 0;
/**
* Count of warnings issued so far
*/
private int warning_count = 0;
/**
* hash tables to hold symbols
*/
private Hashtable keywords = new Hashtable(32);
private Hashtable char_symbols = new Hashtable(32);
private Reader inReader;
private PrintWriter errWriter = null;
/**
* common StringBuffer (suggested by Ginny Travers (bbn.com))
*/
private StringBuffer cmnstrbuf = new StringBuffer();
/**
* Create an instance of Lexer
that reads from input
and
* sends error messages to error
.
*
* @param input input Reader
object
* @param error error output Writer
object
*
* @exception IllegalArgumentException whenever input
is null
*/
public Lexer(Reader input, PrintWriter error) throws IllegalArgumentException {
super();
if (input == null) {
throw new IllegalArgumentException(“Reader cannot be null”);
}
inReader = input;
errWriter = error;
}
/**
* Initialize internal tables and read two characters of input for
* look-ahead purposes.
*
* @exception IOException if advance()
does
* @see Lexer#advance()
*/
public void init() throws IOException {
// set up the keyword table
keywords.put(“strict”, new Integer(Symbols.STRICT));
keywords.put(“strictdigraph”, new Integer(Symbols.STRICTDIGRAPH));
keywords.put(“strictgraph”, new Integer(Symbols.STRICTGRAPH));
keywords.put(“digraph”, new Integer(Symbols.DIGRAPH));
keywords.put(“graph”, new Integer(Symbols.GRAPH));
keywords.put(“subgraph”, new Integer(Symbols.SUBGRAPH));
keywords.put(“node”, new Integer(Symbols.NODE));
keywords.put(“edge”, new Integer(Symbols.EDGE));
keywords.put(“–“, new Integer(Symbols.ND_EDGE_OP));
keywords.put(“->”, new Integer(Symbols.D_EDGE_OP));
// set up the table of single character symbols
char_symbols.put(new Integer(‘;’), new Integer(Symbols.SEMI));
char_symbols.put(new Integer(‘,’), new Integer(Symbols.COMMA));
char_symbols.put(new Integer(‘{‘), new Integer(Symbols.LCUR));
char_symbols.put(new Integer(‘}’), new Integer(Symbols.RCUR));
char_symbols.put(new Integer(‘[‘), new Integer(Symbols.LBR));
char_symbols.put(new Integer(‘]’), new Integer(Symbols.RBR));
char_symbols.put(new Integer(‘=’), new Integer(Symbols.EQUAL));
char_symbols.put(new Integer(‘:’), new Integer(Symbols.COLON));
// read two characters of lookahead
advance();
advance();
}
/**
* Advance the scanner one character in the input stream. This moves
* next_char2 to next_char and then reads a new next_char2.
*
* @exception IOException whenever a problem reading from input
is encountered
*/
public void advance() throws IOException {
if(retreated) {
retreated = false;
int tmp_char = old_char;
old_char = next_char;
next_char = next_char2;
next_char2 = tmp_char;
} else {
old_char = next_char;
next_char = next_char2;
if (next_char == EOF_CHAR) {
next_char2 = EOF_CHAR;
} else {
next_char2 = inReader.read();
}
}
/*
* want to ignore a new-line if preceeding character is a backslash
*/
if (next_char == ‘\\’ && (next_char2 == ‘\n’ || next_char2 == ‘\r’)) {
next_char = next_char2;
next_char2 = inReader.read();
if(next_char == ‘\r’ && next_char2 == ‘\n’) {
next_char = next_char2;
next_char2 = inReader.read();
}
next_char = next_char2;
next_char2 = inReader.read();
}
/*
* want to treat ‘\r’ or ‘\n’ or ‘\r”\n’ as end-of-line,
* but in all cases return only ‘\n’
*/
if(next_char == ‘\r’) {
if(next_char2 == ‘\n’) {
next_char2 = inReader.read();
}
next_char = ‘\n’;
}
// count this
if (old_char == ‘\n’) {
current_line++;
old_position = current_position;
current_position = 1;
} else {
current_position++;
}
}
private void retreat() {
if(retreated) return;
retreated = true;
if(old_char == ‘\n’) {
current_line–;
current_position = old_position;
} else {
current_position–;
}
int tmp_char = next_char2;
next_char2 = next_char;
next_char = old_char;
old_char = tmp_char;
}
/**
* Emit an error message. The message will be marked with both the
* current line number and the position in the line. Error messages
* are printed on print stream passed to Lexer (if any) and a
* GraphParserException is thrown.
*
* @param message the message to print.
*/
private void emit_error(String message) {
String output = “Lexer” + getLocation() + “: ” + message;
if(errWriter != null) {
errWriter.println(“ERROR: ” + output);
}
error_count++;
throw new GraphParserException(output);
}
/**
* Get the current location in the form “[line_number(character_offser)]”.
*
* @return info about the current position in the input
*/
public String getLocation() {
return “[” + current_line + “(” + current_position + “)]”;
}
/**
* Emit a warning message. The message will be marked with both the
* current line number and the position in the line. Messages are
* printed on print stream passed to Lexer (if any).
*
* @param message the message to print.
*/
private void emit_warn(String message) {
if(errWriter != null) {
errWriter.println(“WARNING: Lexer” + getLocation() + “: ” + message);
}
warning_count++;
}
/**
* Check if character is a valid id character;
* @param ch the character in question.
*/
public static boolean id_char(int ch) {
return(Lexer.id_char((char)ch));
}
/**
* Check if character is a valid id character;
* @param ch the character in question.
*/
public static boolean id_char(char ch) {
return((Character.isJavaIdentifierStart(ch) && Character.getType(ch) != Character.CURRENCY_SYMBOL) || Character.isDigit(ch));
}
/**
* Try to look up a single character symbol, returns -1 for not found.
* @param ch the character in question.
*/
private int find_single_char(int ch) {
Integer result;
result = (Integer) char_symbols.get(new Integer((char) ch));
if (result == null) {
return -1;
} else {
return result.intValue();
}
}
/**
* Handle swallowing up a comment. Both old style C and new style C++
* comments are handled.
*/
private void swallow_comment() throws IOException {
// next_char == ‘/’ at this point.
// Is it a traditional comment?
if (next_char2 == ‘*’) {
// swallow the opener
advance();
advance();
// swallow the comment until end of comment or EOF
for (;;) {
// if its EOF we have an error
if (next_char == EOF_CHAR) {
emit_error(“Specification file ends inside a comment”);
return;
}
// if we can see the closer we are done
if (next_char == ‘*’ && next_char2 == ‘/’) {
advance();
advance();
return;
}
// otherwise swallow char and move on
advance();
}
}
// is its a new style comment
if (next_char2 == ‘/’) {
// swallow the opener
advance();
advance();
// swallow to ‘\n’, ‘\f’, or EOF
while (next_char != ‘\n’ && next_char != ‘\f’ && next_char != EOF_CHAR) {
advance();
}
return;
}
// shouldn’t get here, but… if we get here we have an error
emit_error(“Malformed comment in specification — ignored”);
advance();
}
/**
* Swallow up a quote string. Quote strings begin with a double quote
* and include all characters up to the first occurrence of another double
* quote (there is no way to include a double quote inside a quote string).
* The routine returns a Symbol object suitable for return by the scanner.
*/
private Symbol do_quote_string() throws IOException {
String result_str;
// at this point we have lookahead of a double quote — swallow that
advance();
synchronized(cmnstrbuf) {
cmnstrbuf.delete(0,cmnstrbuf.length()); // faster than cmnstrbuf.setLength(0)!
// save chars until we see a double quote
while (!(next_char == ‘”‘)) {
// skip line break
if (next_char == ‘\\’ && next_char2 == ‘”‘) {
advance();
}
// if we have run off the end issue a message and break out of loop
if (next_char == EOF_CHAR) {
emit_error(“Specification file ends inside a code string”);
break;
}
// otherwise record the char and move on
cmnstrbuf.append(new Character((char) next_char));
advance();
}
result_str = cmnstrbuf.toString();
}
// advance past the closing double quote and build a return Symbol
advance();
haveId = true;
return new Symbol(Symbols.ATOM, result_str);
}
/**
* Process an identifier. Identifiers begin with a letter, underscore,
* or dollar sign, which is followed by zero or more letters, numbers,
* underscores or dollar signs. This routine returns an Symbol suitable
* for return by the scanner.
*/
private Symbol do_id() throws IOException {
String result_str;
Integer keyword_num;
char buffer[] = new char[1];
// next_char holds first character of id
buffer[0] = (char) next_char;
synchronized(cmnstrbuf) {
cmnstrbuf.delete(0,cmnstrbuf.length()); // faster than cmnstrbuf.setLength(0)!
cmnstrbuf.append(buffer, 0, 1);
advance();
// collect up characters while they fit in id
while (id_char(next_char)) {
buffer[0] = (char) next_char;
cmnstrbuf.append(buffer, 0, 1);
advance();
}
// extract a string and try to look it up as a keyword
result_str = cmnstrbuf.toString();
}
keyword_num = (Integer) keywords.get(result_str);
// if we found something, return that keyword
if (keyword_num != null) {
haveId = false;
return new Symbol(keyword_num.intValue());
}
// otherwise build and return an id Symbol with an attached string
haveId = true;
return new Symbol(Symbols.ATOM, result_str);
}
/**
* The actual routine to return one Symbol. This is normally called from
* next_token(), but for debugging purposes can be called indirectly from
* debug_next_token().
*/
private Symbol real_next_token() throws IOException {
int sym_num;
for (;;) {
// look for white space
if (next_char == ‘ ‘ || next_char == ‘\t’ || next_char == ‘\n’ ||
next_char == ‘\f’) {
// advance past it and try the next character
advance();
continue;
}
// look for edge operator
if (next_char == ‘-‘) {
if (next_char2 == ‘>’) {
advance();
advance();
haveId = false;
return new Symbol(Symbols.D_EDGE_OP);
} else if (next_char2 == ‘-‘) {
advance();
advance();
haveId = false;
return new Symbol(Symbols.ND_EDGE_OP);
}
}
// look for a single character symbol
sym_num = find_single_char(next_char);
if (sym_num != -1) {
if (sym_num == Symbols.LCUR && !haveId) {
Symbol result = new Symbol(Symbols.SUBGRAPH);
haveId = true;
retreat();
return result;
}
// found one — advance past it and return a Symbol for it
advance();
haveId = false;
return new Symbol(sym_num);
}
// look for quoted string
if (next_char == ‘”‘) {
return do_quote_string();
}
// look for a comment
if (next_char == ‘/’ && (next_char2 == ‘*’ || next_char2 == ‘/’)) {
// swallow then continue the scan
swallow_comment();
continue;
}
// look for an id or keyword
if (id_char(next_char)) {
return do_id();
}
// look for EOF
if (next_char == EOF_CHAR) {
haveId = false;
return new Symbol(Symbols.EOF);
}
// if we get here, we have an unrecognized character
emit_warn(“Unrecognized character ‘” +
new Character((char) next_char) + “‘(” + next_char +
“) — ignored”);
// advance past it
advance();
}
}
/**
* Return one Symbol. This method is the main external interface to
* the scanner.
* It consumes sufficient characters to determine the next input Symbol
* and returns it.
*
* @exception IOException if advance()
does
*/
public Symbol next_token(int debugLevel) throws IOException {
if(debugLevel > 0) {
Symbol result = real_next_token();
if(errWriter != null && debugLevel >= 5) {
errWriter.println(“DEBUG: Lexer: next_token() => ” + result.sym);
}
return result;
} else {
return real_next_token();
}
}
}
att/grappa/Node.java
att/grappa/Node.java/*
* This software may only be used by you under license from AT&T Corp.
* (“AT&T”). A copy of AT&T’s Source Code Agreement is available at
* AT&T’s Internet website having the URL:
*
* If you received this software without first entering into a license
* with AT&T, you have an infringing copy of this software and cannot use
* it without violating AT&T’s intellectual property rights.
*/
package att.grappa;
import java.util.*;
import java.io.*;
import java.awt.Color;
import java.awt.geom.Point2D;
/**
* This class describes a node.
*
* @version 1.2, 26 May 2005; Copyright 1996 – 2005 by AT&T Corp.
* @author John Mocenigo, Research @ AT&T Labs
*/
public class Node extends Element
{
/**
* Default node name prefix used by setName().
*
* @see setName()
*/
public final static String defaultNamePrefix = “N”;
// vector of edges going into the node
private Vector inEdges = null;
// vector of edges going out of the node
private Vector outEdges = null;
// vector of edge ports (not used yet)
private Vector Ports = null;
/**
* Use this constructor when creating a node within a subgraph.
*
* @param subg the parent subgraph.
* @param name the name of this node.
*/
public Node(Subgraph subg, String name) {
super(Grappa.NODE,subg);
setName(name);
nodeAttrsOfInterest();
}
/**
* Use this constructor when creating a node within a subgraph
* with an automatically generated name.
*
* @param subg the parent subgraph.
* @see setName()
*/
public Node(Subgraph subg) {
this(subg,(String)null);
}
// a listing of the attributes of interest for Nodes
private void nodeAttrsOfInterest() {
attrOfInterest(DISTORTION_ATTR);
attrOfInterest(HEIGHT_ATTR);
attrOfInterest(ORIENTATION_ATTR);
attrOfInterest(PERIPHERIES_ATTR);
attrOfInterest(POS_ATTR);
attrOfInterest(SIDES_ATTR);
attrOfInterest(SKEW_ATTR);
attrOfInterest(STYLE_ATTR);
attrOfInterest(WIDTH_ATTR);
}
// override Element methods
/**
* Check if this element is a node.
* Useful for testing the subclass type of an Element object.
*
* @return true if this object is a Node.
*/
public boolean isNode() {
return(true);
}
/**
* Get the type of this element.
* Useful for distinguishing among Element objects.
*
* @return the class variable constant Grappa.NODE
* @see Grappa#NODE
*/
public int getType() {
return(Grappa.NODE);
}
/**
* Generates and sets the name for this node.
* The generated name is the concatenation of Node.defaultNamePrefix
* with the numeric id of this node instance.
*
* @see Node#defaultNamePrefix
* @see Element#getId()
*/
void setName() {
String oldName = name;
while(true) {
name = Node.defaultNamePrefix + getId() + “_” + System.currentTimeMillis();
if(getGraph().findNodeByName(name) == null) {
break;
}
}
// update subgraph node dictionary
if(oldName != null) {
getSubgraph().removeNode(oldName);
}
getSubgraph().addNode(this);
canonName = null;
resetEdgeNames();
}
/**
* Sets the node name to the supplied argument.
* When the argument is null, setName() is called.
*
* @exception IllegalArgumentException when newName is not unique.
* @param newName the new name for the node.
* @see Node#setName()
*/
public void setName(String newName) throws IllegalArgumentException {
if(newName == null) {
setName();
return;
}
String oldName = name;
// test if name is the same as the old name (if any)
if(oldName != null && oldName.equals(newName)) {
return;
}
// is name unique?
if(getGraph().findNodeByName(newName) != null) {
throw new IllegalArgumentException(“node name (” + newName + “) is not unique”);
}
// update subgraph node dictionary
if(oldName != null) {
getSubgraph().removeNode(oldName);
}
name = newName;
getSubgraph().addNode(this);
canonName = null;
resetEdgeNames();
}
private void resetEdgeNames() {
Edge edge;
if (inEdges != null) {
for(int i = 0; i < inEdges.size(); i++) {
edge = (Edge)(inEdges.elementAt(i));
edge.canonName = null;
}
}
if (outEdges != null) {
for(int i = 0; i < outEdges.size(); i++) {
edge = (Edge)(outEdges.elementAt(i));
edge.canonName = null;
}
}
}
/**
* Add the given edge to this node's inEdges or outEdges dictionaries,
* if it is not already there.
* The boolean indicates whether the edge terminates at (inEdge) or
* emanates from (outEdge) the node.
*
* @param edge the edge to be added to this node's dictionary.
* @param inEdge if set true, add to inEdges dictionary otherwise add
* to outEdges dictionary.
* @see Edge
*/
synchronized public void addEdge(Edge edge, boolean inEdge) {
if(edge == null) return;
if(inEdge) {
if(inEdges == null) {
inEdges = new Vector();
}
if(!inEdges.contains(edge)) {
inEdges.addElement(edge);
}
} else {
if(outEdges == null) {
outEdges = new Vector();
}
outEdges.addElement(edge);
if(!outEdges.contains(edge)) {
outEdges.addElement(edge);
}
}
}
/**
* Find an outbound edge given its head and key.
*
* @param head the Node at the head of the edge
* @param key the key String associated with the edge
*
* @return the matching edge or null
*/
public Edge findOutEdgeByKey(Node head, String key) {
if(head == null || key == null || outEdges == null) {
return null;
}
Edge edge = null;
for(int i = 0; i < outEdges.size(); i++) {
edge = (Edge)(outEdges.elementAt(i));
if(head == edge.getHead() && key.equals(edge.getKey())) {
return edge;
}
}
return null;
}
/**
* Find an inbound edge given its tail and key.
*
* @param tail the Node at the tail of the edge
* @param key the key String associated with the edge
*
* @return the matching edge or null
*/
public Edge findInEdgeByKey(Node tail, String key) {
if(tail == null || key == null || inEdges == null) {
return null;
}
Edge edge = null;
for(int i = 0; i < inEdges.size(); i++) {
edge = (Edge)(inEdges.elementAt(i));
if(tail == edge.getTail() && key.equals(edge.getKey())) {
return edge;
}
}
return null;
}
/**
* Returns the center point of the node.
* as determined from the height
* and width attributes of the node.
*
* @return the node's center point.
*/
public GrappaPoint getCenterPoint() {
GrappaPoint pt = (GrappaPoint)getAttributeValue(POS_ATTR);
if(pt == null) { // this should never be null, but just in case...
pt = new GrappaPoint();
} else if(!Grappa.centerPointNodes) {
Double w = (Double)getAttributeValue(WIDTH_ATTR);
Double h = (Double)getAttributeValue(HEIGHT_ATTR);
if(w != null && h != null) { // these should never be null, but...
pt = new GrappaPoint(pt.x - (w.doubleValue()/2.0), pt.y - (h.doubleValue()/2.0));
}
} else {
pt = new GrappaPoint(pt.x, pt.y); // return copy
}
return(pt);
}
/**
* Remove the given edge from this node's inEdges or outEdges dictionaries.
* The boolean indicates whether the edge terminates at (inEdge) or
* emanates from (outEdge) the node.
*
* @param edge the edge to be removed from this node's dictionary.
* @param inEdge if set true, remove from inEdges dictionary otherwise
* remove from outEdges dictionary.
* @see Edge
*/
synchronized public void removeEdge(Edge edge, boolean inEdge) {
if(edge == null) return;
if(inEdge) {
if(inEdges == null) return;
inEdges.removeElement(edge);
} else {
if(outEdges == null) return;
outEdges.removeElement(edge);
}
}
/**
* Print the node description to the provided stream.
*
* @param out the output text stream for writing the description.
*/
public void printNode(PrintWriter out) {
this.printElement(out);
}
/**
* Returns the attribute conversion type for the supplied attribute name.
* After node specific attribute name/type mappings are checked, mappings
* at the element level are checked.
*
* @param attrname the attribute name
* @return the currently associated attribute type
*/
public static int attributeType(String attrname) {
int convtype = -1;
int hashCode;
if(attrname != null) {
hashCode = attrname.hashCode();
if(hashCode == DISTORTION_HASH && attrname.equals(DISTORTION_ATTR)) {
convtype = DOUBLE_TYPE;
} else if(hashCode == ORIENTATION_HASH && attrname.equals(ORIENTATION_ATTR)) {
convtype = DOUBLE_TYPE;
} else if(hashCode == PERIPHERIES_HASH && attrname.equals(PERIPHERIES_ATTR)) {
convtype = INTEGER_TYPE;
} else if(hashCode == POS_HASH && attrname.equals(POS_ATTR)) {
convtype = POINT_TYPE;
} else if(hashCode == SHAPE_HASH && attrname.equals(SHAPE_ATTR)) {
convtype = SHAPE_TYPE;
} else if(hashCode == SIDES_HASH && attrname.equals(SIDES_ATTR)) {
convtype = INTEGER_TYPE;
} else if(hashCode == SKEW_HASH && attrname.equals(SKEW_ATTR)) {
convtype = DOUBLE_TYPE;
} else {
return(Element.attributeType(attrname));
}
}
return(convtype);
}
/**
* Get an Enumeration of the edges directed to or from this node.
*
* @return an Enumeration of all the edges (in or out) associated with this node.
*/
public Enumeration edgeElements() {
return new Enumerator(inEdges, outEdges);
}
/**
* Get an Enumeration of the edges directed to this node.
*
* @return an Enumeration of all the inbound edges associated with this node.
*/
public Enumeration inEdgeElements() {
return new Enumerator(inEdges, null);
}
/**
* Get an Enumeration of the edges directed from this node.
*
* @return an Enumeration of all the outbound edges associated with this node.
*/
public Enumeration outEdgeElements() {
return new Enumerator(null, outEdges);
}
class Enumerator implements Enumeration {
int inCnt = 0;
int outCnt = 0;
Vector inEdges = null;
Vector outEdges = null;
Enumerator(Vector inEdges, Vector outEdges) {
inCnt = (inEdges == null) ? 0 : inEdges.size();
outCnt = (outEdges == null) ? 0 : outEdges.size();
this.inEdges = inEdges;
this.outEdges = outEdges;
}
public boolean hasMoreElements() {
int tmp;
if(inCnt > 0 && inCnt > (tmp = inEdges.size())) inCnt = tmp;
if(outCnt > 0 && outCnt > (tmp = outEdges.size())) outCnt = tmp;
return((inCnt+outCnt) > 0);
}
public Object nextElement() {
synchronized (Node.this) {
int tmp;
if(inCnt > 0 && inCnt > (tmp = inEdges.size())) inCnt = tmp;
if(inCnt > 0) {
return inEdges.elementAt(–inCnt);
}
if(outCnt > 0 && outCnt > (tmp = outEdges.size())) outCnt = tmp;
if(outCnt > 0) {
return outEdges.elementAt(–outCnt);
}
throw new NoSuchElementException(“Node$Enumerator”);
}
}
}
}
// JavaCup specification for a graph definition of the type generated by `dot’
package att.grappa;
// The next 18 comment line need to be manually copied to Parser.java after JavaCup generation.
/**
* This class provides a parser for the dot graph representation format.
* It is used in conjunction with JavaCup, a yacc-like parser generator
* originally by:
*
*
* Scott E. Hudson
* Graphics Visualization and Usability Center
* Georgia Institute of Technology
*
*
* and more recently modified and maintained by
*
* a number of people at Princeton University.
*
* @version 1.2, 14 Feb 2001; Copyright 1996 – 2001 by AT&T Corp.
* @author John Mocenigo, Research @ AT&T Labs
*/
import java.io.*;
import java.util.*;
import java_cup.runtime.*;
action code {:
// a list of variables used in action code during grammar translation
//Parser parser = null;
Subgraph rootSubgraph;
Subgraph lastSubgraph;
Graph graph;
Subgraph thisGraph;
Node thisNode;
Edge thisEdge;
Node fromNode;
Node toNode;
String portName = null;
String toPortName;
String fromPortName;
int thisAttrType;
int thisElemType;
boolean directed = true;
String graphType;
private int anon_id = 0;
Vector attrs = new Vector(8,4);
Vector nodes = new Vector(8,4);
Vector edges = new Vector(8,4);
void appendAttr(String name, String value) {
attrs.addElement(new Attribute(thisElemType,name,value));
}
void noMacros() {
parser.report_error(“attribute macros are not supported yet”, null);
}
void attrStmt(int kind, String macroName) {
if(macroName != null) {
noMacros();
return;
}
if(attrs.size() == 0) return;
Attribute attr = null;
for(int i = 0; i < attrs.size(); i++) {
if((attr = (Attribute)(attrs.elementAt(i))).getValue() == null) {
// null means to not attach the attribute to an element
continue;
} else {
switch(kind) {
case Grappa.NODE:
parser.debug_message(1, "adding node default attr (" + attr.getName() + ") to thisGraph(" + thisGraph.getName() + ")");
thisGraph.setNodeAttribute(attr);
break;
case Grappa.EDGE:
parser.debug_message(1, "adding edge default attr (" + attr.getName() + ") to thisGraph(" + thisGraph.getName() + ")");
thisGraph.setEdgeAttribute(attr);
break;
case Grappa.SUBGRAPH:
parser.debug_message(1, "adding subg default attr (" + attr.getName() + ") to thisGraph(" + thisGraph.getName() + ")");
thisGraph.setAttribute(attr);
break;
}
}
}
attrs.removeAllElements();
}
void startGraph(String name, boolean type, boolean strict) {
if(graph == null) {
graph = new Graph(name, type, strict);
} else {
graph.reset(name, type, strict);
}
directed = type;
rootSubgraph = (Subgraph)graph;
parser.debug_message(1, "Creating top level graph (" + name + ")");
anon_id = 0;
}
void openGraph() {
thisGraph = rootSubgraph;
thisElemType = Grappa.SUBGRAPH;
parser.debug_message(1, "thisGraph(" + thisGraph.getName() + ")");
}
void closeGraph() {
int level = 1;
if(parser.getErrorWriter() != null && parser.getDebugLevel() >= level) {
parser.debug_message(level, “parsed graph follows:”);
rootSubgraph.printSubgraph(parser.getErrorWriter());
}
}
void openSubg(String name) {
thisGraph = new Subgraph(thisGraph, name);
parser.debug_message(1, “thisGraph(” + thisGraph.getName() + “)”);
thisElemType = Grappa.SUBGRAPH;
}
String anonStr() {
return Grappa.ANONYMOUS_PREFIX + anon_id++;
}
void closeSubg() {
lastSubgraph = thisGraph;
// getSubgraph() gets the parent subgraph
thisGraph = thisGraph.getSubgraph();
if(thisGraph == null) {
parser.report_error (“parser attempted to go above root Subgraph”, null);
thisGraph = rootSubgraph;
}
parser.debug_message(1, “Created subgraph (” + lastSubgraph.getName() + “) in subgraph (” + thisGraph.getName() + “)…”);
parser.debug_message(1, “thisGraph(” + thisGraph.getName() + “)”);
}
void appendNode(String name, String port) {
if((thisNode = rootSubgraph.findNodeByName(name)) == null) {
parser.debug_message(1, “Creating node in subgraph (” + thisGraph.getName() + “)…”);
thisNode = new Node(thisGraph, name);
} else {
parser.debug_message(1, “Node already in subgraph (” + thisNode.getSubgraph().getName() + “)…”);
}
Object[] pair = new Object[2];
pair[0] = thisNode;
pair[1] = port;
nodes.addElement(pair);
parser.debug_message(1, “thisNode(” + thisNode.getName() + “)”);
thisElemType = Grappa.NODE;
}
void nodeWrap() {
Object[] pair = null;
if(nodes.size() > 0 && attrs.size() > 0) {
for(int i = 0; i < nodes.size(); i++) {
pair = (Object[])(nodes.elementAt(i));
applyAttrs((Element)pair[0],null,null);
}
}
attrs.removeAllElements();
nodes.removeAllElements();
}
void bufferEdges() {
Object[] pair = new Object[2];
if(nodes.size() > 0) {
pair[0] = nodes;
nodes = new Vector(8,4);
pair[1] = new Boolean(true);
} else if(lastSubgraph != null) {
pair[0] = lastSubgraph;
lastSubgraph = null;
pair[1] = new Boolean(false);
} else {
parser.report_error (“EDGE_OP without clear antecedent nodelist or subgraph”, null);
return;
}
edges.addElement(pair);
}
void edgeWrap() {
bufferEdges();
Attribute key = null;
Attribute name = null;
Attribute attr = null;
int skip = -1;
for(int i = 0; i < attrs.size(); i++) {
attr = (Attribute)(attrs.elementAt(i));
if(attr.getName().equals("key")) {
key = attr;
if(name != null)
break;
} else if(attr.getName().equals("__nAmE__")) {
name = attr;
if(key != null)
break;
}
}
Object[] tailPair = (Object[])(edges.elementAt(0));
Object[] headPair = null;
// note: when node list is used, a non-null name will cause errors
// due to lack of uniqueness
for(int i = 1; i < edges.size(); i++) {
headPair = (Object[])(edges.elementAt(i));
if(((Boolean)(tailPair[1])).booleanValue()) { // true if node list
Vector list = (Vector)(tailPair[0]);
Object[] nodePair = null;
for(int j = 0; j < list.size(); j++) {
nodePair = (Object[])(list.elementAt(j));
edgeRHS((Node)(nodePair[0]),(String)(nodePair[1]),headPair,key,name);
}
list.removeAllElements();
} else {
Subgraph subg = (Subgraph)(tailPair[0]);
Enumeration enm = subg.elements(Grappa.NODE);
while(enm.hasMoreElements()) {
edgeRHS((Node)(enm.nextElement()),null,headPair,key,name);
}
}
tailPair = headPair;
}
edges.removeAllElements();
attrs.removeAllElements();
}
void edgeRHS(Node tail, String tailPort, Object[] headPair, Attribute keyAttr, Attribute nameAttr) {
String key = (keyAttr == null) ? null : keyAttr.getStringValue();
String name = (nameAttr == null) ? null : nameAttr.getStringValue();
if(((Boolean)(headPair[1])).booleanValue()) { // true if node list
Vector list = (Vector)(headPair[0]);
Object[] nodePair = null;
for(int j = 0; j < list.size(); j++) {
nodePair = (Object[])(list.elementAt(j));
thisEdge = new Edge(thisGraph, tail, tailPort, (Node)(nodePair[0]), (String)(nodePair[1]), key, name);
parser.debug_message(1, "Creating edge in subgraph (" + thisGraph.getName() + ")...");
parser.debug_message(1, "thisEdge(" + thisEdge.getName() + ")");
thisElemType = Grappa.EDGE;
applyAttrs((Element)thisEdge,keyAttr,nameAttr);
}
} else {
Subgraph subg = (Subgraph)(headPair[0]);
Enumeration enm = subg.elements(Grappa.NODE);
while(enm.hasMoreElements()) {
thisEdge = new Edge(thisGraph, tail, tailPort, (Node)(enm.nextElement()), null, key, name);
parser.debug_message(1, "Creating edge in subgraph (" + thisGraph.getName() + ")...");
parser.debug_message(1, "thisEdge(" + thisEdge.getName() + ")");
thisElemType = Grappa.EDGE;
applyAttrs((Element)thisEdge,keyAttr,nameAttr);
}
}
}
void applyAttrs(Element elem, Attribute skip1, Attribute skip2) {
Attribute attr = null;
for(int i = 0; i < attrs.size(); i++) {
attr = (Attribute)attrs.elementAt(i);
if(attr == skip1) continue;
else if(attr == skip2) continue;
elem.setAttribute(attr);
}
}
:};
// a method to get the final result from caller to the parser
parser code {:
private Graph theGraph = null;
private Reader inReader;
private PrintWriter errWriter;
private Lexer lexer;
private int debugLevel = 0;
/**
* Create an instance of Parser
with input, error output and
* a supplied Graph
object. The graph object is cleared (reset) before
* new graph components are added to it by this parsing operation.
*
* @param inputReader input Reader
object
* @param errorWriter error output Writer
object (or null to suppress error output)
* @param graph Graph
object for storing parsed graph information (or null to create a new object)
*/
public Parser (Reader inputReader, PrintWriter errorWriter, Graph graph) {
super ();
inReader = inputReader;
errWriter = errorWriter;
theGraph = graph;
lexer = new Lexer (inputReader, errorWriter);
}
/**
* A convenience constructor equivalent to Parser(inputReader,errorWriter,null)
.
*
* @param inputReader input Reader
object
* @param errorWriter error output Writer
object (or null to suppress error output)
*/
public Parser (Reader inputReader, PrintWriter errorWriter) {
this(inputReader,errorWriter,null);
}
/**
* A convenience constructor equivalent to Parser(inputReader,null,null)
.
*
* @param inputReader input Reader
object
*/
public Parser (Reader inputReader) {
this(inputReader,(PrintWriter)null,null);
}
/**
* Create an instance of Parser
with input, error output and
* a supplied Graph
object. The input stream is converted to
* a Reader
and the error stream is converted to a Writer
.
*
* @param inputStream input InputStream
object
* @param errorStream error output OutputStream
object (or null to suppress error output)
* @param graph Graph
object for storing parsed graph information (or null to create a new object)
*/
public Parser (InputStream inputStream, OutputStream errorStream, Graph graph) {
this(new InputStreamReader(inputStream),new PrintWriter(errorStream,true),graph);
}
/**
* A convenience constructor equivalent to Parser(inputStream,errorStream,null)
.
*
* @param inputStream input InputStream
object
* @param errorStream error output OutputStream
object
*/
public Parser (InputStream inputStream, OutputStream errorStream) {
this(new InputStreamReader(inputStream),new PrintWriter(errorStream,true),null);
}
/**
* A convenience constructor equivalent to Parser(inputStream,null,null)
.
*
* @param inputStream input InputStream
object
*/
public Parser (InputStream inputStream) {
this(new InputStreamReader(inputStream),(PrintWriter)null,null);
}
/**
* Get the Lexer
object associated with this parser.
*
* @return the associated lexical analyzer.
*/
public Lexer getLexer() {
return lexer;
}
/**
* Get the error writer, if any, for this parser.
*
* @return the error writer for this parser.
*/
public PrintWriter getErrorWriter() {
return(errWriter);
}
/**
* Get the debug level for this parser.
* The debug level is set to a non-zero value by calling debug_parse
.
*
* @return the debug level of this parser.
* @see Parser#debug_parse(int)
*/
public int getDebugLevel() {
return(debugLevel);
}
/**
* Report a fatal error.
* Calling this method will throw a GraphParserException
.
*
* @param message the error message to send to the error stream and include in the thrown exception
* @param info not used
*
* @exception GraphParserException whenver this method is called
*/
public void report_error(String message, Object info) throws GraphParserException {
String loc = getLexer().getLocation();
if(errWriter != null) {
errWriter.println(“ERROR: Parser” + loc + “: ” + message);
}
throw new GraphParserException(“at ” + loc + “: ” + message);
}
/**
* Report a non-fatal error.
*
* @param message the warning message to send to the error stream, if the stream non-null.
* @param info not used
*/
public void report_warning(String message, Object info) {
String loc = getLexer().getLocation();
if(errWriter != null) {
errWriter.println(“WARNING: Parser” + loc + “: ” + message);
}
}
/**
* Write a debugging message to the error stream.
* The debug level of the message is 5.
*
* @param message the debug message to send to the error stream, if the stream non-null.
* @see Parser#debug_message(int,String)
*/
public void debug_message(String message) {
debug_message(5, message);
}
/**
* Write a debugging message to the error stream.
* A message is written only if the error stream is not null and the
* debug level of the message is greater than or equal to the debugging
* level of the parser.
*
* @param level the level of the message
* @param message the debug message to send to the error stream, if the stream non-null.
* @see Parser#getDebugLevel()
*/
public void debug_message(int level, String message) {
if(debugLevel < level) {
return;
}
String loc = getLexer().getLocation();
if(errWriter != null) {
errWriter.println("DEBUG: Parser" + loc + ": " + message);
}
}
/**
* Invokes the parser in debug mode.
* The lowering the debug level reduces the amount of debugging output.
* A level of 0 inhibits all debugging messages, generally a level of 10
* will let all messages get through.
*
* @param debug the debug level to use for filtering debug messages based on priority.
* @exception Exception if parse()
does
*/
public Symbol debug_parse(int debug) throws java.lang.Exception {
if(debug == 0) {
return parse();
}
debugLevel = debug;
/* the current action code */
int act;
/* the Symbol/stack element returned by a reduce */
Symbol lhs_sym = null;
/* information about production being reduced with */
short handle_size, lhs_sym_num;
/* set up direct reference to tables to drive the parser */
production_tab = production_table();
action_tab = action_table();
reduce_tab = reduce_table();
debug_message(5, “# Initializing parser”);
/* initialize the action encapsulation object */
init_actions();
/* do user initialization */
user_init();
/* the current Symbol */
cur_token = scan();
debug_message(5, “# Current Symbol is #” + cur_token.sym);
/* push dummy Symbol with start state to get us underway */
stack.push(new Symbol(0, start_state()));
tos = 0;
/* continue until we are told to stop */
for (_done_parsing = false; !_done_parsing; )
{
/* current state is always on the top of the stack */
/* look up action out of the current state with the current input */
act = get_action(((Symbol)stack.peek()).parse_state, cur_token.sym);
/* decode the action — > 0 encodes shift */
if (act > 0)
{
/* shift to the encoded state by pushing it on the stack */
cur_token.parse_state = act-1;
debug_shift(cur_token);
stack.push(cur_token);
tos++;
/* advance to the next Symbol */
cur_token = scan();
debug_message(5, “# Current token is #” + cur_token.sym);
}
/* if its less than zero, then it encodes a reduce action */
else if (act < 0)
{
/* perform the action for the reduce */
lhs_sym = do_action((-act)-1, this, stack, tos);
/* look up information about the production */
lhs_sym_num = production_tab[(-act)-1][0];
handle_size = production_tab[(-act)-1][1];
debug_reduce((-act)-1, lhs_sym_num, handle_size);
/* pop the handle off the stack */
for (int i = 0; i < handle_size; i++)
{
stack.pop();
tos--;
}
/* look up the state to go to from the one popped back to */
act = get_reduce(((Symbol)stack.peek()).parse_state, lhs_sym_num);
/* shift to that state */
lhs_sym.parse_state = act;
stack.push(lhs_sym);
tos++;
debug_message(5, "# Goto state #" + act);
}
/* finally if the entry is zero, we have an error */
else if (act == 0)
{
/* call user syntax error reporting routine */
syntax_error(cur_token);
/* try to error recover */
if (!error_recovery(true))
{
/* if that fails give up with a fatal syntax error */
unrecovered_syntax_error(cur_token);
/* just in case that wasn't fatal enough, end parse */
done_parsing();
} else {
lhs_sym = (Symbol)stack.peek();
}
}
}
return lhs_sym;
}
CUP$Parser$actions getActionObject () {
return action_obj;
}
/**
* Get the graph resulting from the parsing operations.
*
* @return the graph generated from the input.
*/
public Graph getGraph () {
return action_obj.graph;
}
:};
// Preliminaries to set up and use the scanner.
init with {:
lexer.init();
action_obj.graph = theGraph;
//action_obj.parser = this;
:};
scan with {: return lexer.next_token(debugLevel); :};
// Terminals (tokens returned by the scanner).
terminal Integer GRAPH, NODE, EDGE, SUBGRAPH, D_EDGE_OP, ND_EDGE_OP;
terminal STRICT, DIGRAPH, STRICTGRAPH, STRICTDIGRAPH;
terminal SEMI, COMMA, LCUR, RCUR, LBR, RBR, EQUAL, COLON, ATSIGN;
terminal String ATOM;
// Non terminals
non terminal Boolean optStrict, graphType, rCompound;
non terminal Integer attrType;
non terminal String optSubgHdr, optGraphName, optMacroName, optPort;
non terminal graph, hdr, body, optStmtList, stmtList, stmt;
non terminal attrStmt, optSemi, optSeparator, compound, simple, optAttr;
non terminal nodeList, subgraph, node, attrList, graphAttrDefs, optAttrDefs;
non terminal attrDefs, attrItem, attrAssignment, attrMacro, edge_op;
start with graph;
// the grammar
graph ::= hdr
{:
openGraph();
:} body
{:
closeGraph();
:}
| error:val
{:
//CUP$parser.report_error ("An error was encountered while graph parsing (" + val.toString() + ").", null);
parser.report_error ("An error was encountered while graph parsing (" + val.toString() + ").", null);
:}
| /* empty */
{:
graph = new Graph("empty");
//((Parser)(CUP$parser)).report_warning ("The graph to parse is empty.", null);
((Parser)(parser)).report_warning ("The graph to parse is empty.", null);
:}
;
hdr ::= optStrict:strict graphType:type optGraphName:name
{:
startGraph(name,type.booleanValue(),strict.booleanValue());
:}
| STRICTGRAPH optGraphName:name
{:
startGraph(name,true,false);
:}
| STRICTDIGRAPH optGraphName:name
{:
startGraph(name,true,true);
:}
;
optStrict ::= STRICT
{:
RESULT = new Boolean(true);
:}
| /* empty */
{:
RESULT = new Boolean(false);
:}
;
graphType ::= GRAPH
{:
RESULT = new Boolean(false);
:}
| DIGRAPH
{:
RESULT = new Boolean(true);
:}
;
optGraphName ::= ATOM:val
{:
RESULT = val;
:}
| // empty
{:
RESULT = anonStr();
:}
;
body ::= LCUR optStmtList RCUR
;
optStmtList ::= stmtList
| // empty
;
stmtList ::= stmtList stmt
| stmt
;
stmt ::= attrStmt optSemi
| compound optSemi
;
compound ::= simple rCompound:val optAttr
{:
if (val.booleanValue()) edgeWrap();
else nodeWrap();
:}
;
simple ::= nodeList
| subgraph
;
edge_op ::= D_EDGE_OP
{:
if(!directed) {
//CUP$parser.report_error ("attempt to create a directed edge in a non-directed graph",null);
parser.report_error ("attempt to create a directed edge in a non-directed graph",null);
}
:}
| ND_EDGE_OP
{:
if(directed) {
//CUP$parser.report_error ("attempt to create a non-directed edge in a directed graph",null);
parser.report_error ("attempt to create a non-directed edge in a directed graph",null);
}
:}
;
rCompound ::= edge_op
{:
thisElemType = Grappa.EDGE;
bufferEdges();
:} simple rCompound:val
{:
thisElemType = Grappa.EDGE;
RESULT = new Boolean(true);
:}
| // empty
{:
thisElemType = Grappa.NODE;
RESULT = new Boolean(false);
:}
;
nodeList ::= node
| nodeList COMMA node
;
node ::= ATOM:name optPort:port
{:
appendNode(name,port);
:}
;
optPort ::= COLON ATOM:val // ignore port IDs
{:
RESULT = val;
:}
| // empty
{:
RESULT = null;
:}
;
attrStmt ::= attrType:type optMacroName:name attrList
{:
attrStmt(type.intValue(),name);
:}
| graphAttrDefs
{:
attrStmt(Grappa.SUBGRAPH,null);
:}
;
attrType ::= GRAPH:val
{:
RESULT = new Integer(Grappa.SUBGRAPH);
:}
| NODE:val
{:
RESULT = new Integer(Grappa.NODE);
:}
| EDGE:val
{:
RESULT = new Integer(Grappa.EDGE);
:}
;
optMacroName ::= ATOM:val EQUAL
{:
RESULT = val;
:}
| // empty
{:
RESULT = null;
:}
;
optAttr ::= attrList
| // empty
;
attrList ::= optAttr LBR optAttrDefs RBR
;
optAttrDefs ::= attrDefs
| // empty
;
attrDefs ::= attrItem
| attrDefs optSeparator attrItem
;
attrItem ::= attrAssignment
| attrMacro
;
attrAssignment ::= ATOM:name EQUAL ATOM:value
{:
appendAttr(name,value);
:}
;
attrMacro ::= ATSIGN ATOM:name // not yet implemented
{:
appendAttr(name,null);
:}
;
graphAttrDefs ::= attrAssignment
;
subgraph ::= optSubgHdr:val
{:
openSubg(val);
:} body
{:
closeSubg();
:}
;
optSubgHdr ::= SUBGRAPH ATOM:val
{:
RESULT = val;
:}
| SUBGRAPH
{:
RESULT = anonStr();
:}
| // empty
{:
RESULT = anonStr();
:}
;
optSemi ::= SEMI
| // empty
;
optSeparator ::= SEMI
| COMMA
| // empty
;
att/grappa/Parser.java
att/grappa/Parser.java
//----------------------------------------------------
// The following code was generated by CUP v0.10k
// Wed May 25 19:10:51 EDT 2005
//----------------------------------------------------
package att.grappa;
import java.io.*;
import java.util.*;
import java_cup.runtime.*;
/** CUP v0.10k generated parser.
* @version Wed May 25 19:10:51 EDT 2005
*/
/**
* This class provides a parser for the dot graph representation format.
* It is used in conjunction with JavaCup, a yacc-like parser generator
* originally by:
*
*
* Scott E. Hudson
* Graphics Visualization and Usability Center
* Georgia Institute of Technology
*
*
* and more recently modified and maintained by
*
* a number of people at Princeton University.
*
* @version 1.2, 26 May 2005; Copyright 1996 – 2005 by AT&T Corp.
* @author John Mocenigo, Research @ AT&T Labs
*/
public class Parser extends java_cup.runtime.lr_parser {
/** Default constructor. */
public Parser() {super();}
/** Constructor which sets the default scanner. */
public Parser(java_cup.runtime.Scanner s) {super(s);}
/** Production table. */
protected static final short _production_table[][] =
unpackFromStrings(new String[] {
“\000\077\000\002\002\004\000\002\042\002\000\002\013” +
“\005\000\002\013\003\000\002\013\002\000\002\014\005” +
“\000\002\014\004\000\002\014\004\000\002\003\003\000” +
“\002\003\002\000\002\004\003\000\002\004\003\000\002” +
“\010\003\000\002\010\002\000\002\015\005\000\002\016” +
“\003\000\002\016\002\000\002\017\004\000\002\017\003” +
“\000\002\020\004\000\002\020\004\000\002\024\005\000” +
“\002\025\003\000\002\025\003\000\002\041\003\000\002” +
“\041\003\000\002\043\002\000\002\005\006\000\002\005” +
“\002\000\002\027\003\000\002\027\005\000\002\031\004” +
“\000\002\012\004\000\002\012\002\000\002\021\005\000” +
“\002\021\003\000\002\006\003\000\002\006\003\000\002” +
“\006\003\000\002\011\004\000\002\011\002\000\002\026” +
“\003\000\002\026\002\000\002\032\006\000\002\034\003” +
“\000\002\034\002\000\002\035\003\000\002\035\005\000” +
“\002\036\003\000\002\036\003\000\002\037\005\000\002” +
“\040\004\000\002\033\003\000\002\044\002\000\002\030” +
“\005\000\002\007\004\000\002\007\003\000\002\007\002” +
“\000\002\022\003\000\002\022\002\000\002\023\003\000” +
“\002\023\003\000\002\023\002” });
/** Access to production table. */
public short[][] production_table() {return _production_table;}
/** Parse-action table. */
protected static final short[][] _action_table =
unpackFromStrings(new String[] {
“\000\121\000\020\002\ufffd\003\010\004\ufff8\012\007\013” +
“\ufff8\014\004\015\005\001\002\000\006\020\ufff4\027\120” +
“\001\002\000\006\020\ufff4\027\120\001\002\000\006\004” +
“\117\013\116\001\002\000\006\004\ufff9\013\ufff9\001\002” +
“\000\004\002\ufffe\001\002\000\004\002\114\001\002\000” +
“\004\020\000\001\002\000\004\020\015\001\002\000\004” +
“\002\uffff\001\002\000\020\004\026\005\037\006\025\007” +
“\016\020\uffc8\021\ufff1\027\022\001\002\000\006\020\uffc9” +
“\027\113\001\002\000\022\004\uffcd\005\uffcd\006\uffcd\007” +
“\uffcd\016\uffcd\020\uffcd\021\uffcd\027\uffcd\001\002\000\022” +
“\004\uffde\005\uffde\006\uffde\007\uffde\016\uffde\020\uffde\021” +
“\uffde\027\uffde\001\002\000\004\021\112\001\002\000\036” +
“\004\uffe0\005\uffe0\006\uffe0\007\uffe0\010\uffe0\011\uffe0\016” +
“\uffe0\017\uffe0\020\uffe0\021\uffe0\022\uffe0\024\063\025\071” +
“\027\uffe0\001\002\000\030\004\uffea\005\uffea\006\uffea\007” +
“\uffea\010\uffea\011\uffea\016\uffea\020\uffea\021\uffea\022\uffea” +
“\027\uffea\001\002\000\004\020\uffcc\001\002\000\006\022” +
“\uffdb\027\uffdb\001\002\000\006\022\uffdd\027\uffdd\001\002” +
“\000\032\004\uffe4\005\uffe4\006\uffe4\007\uffe4\010\uffe4\011” +
“\uffe4\016\uffe4\017\uffe4\020\uffe4\021\uffe4\022\uffe4\027\uffe4” +
“\001\002\000\022\004\uffc6\005\uffc6\006\uffc6\007\uffc6\016” +
“\074\020\uffc6\021\uffc6\027\uffc6\001\002\000\030\004\uffe5” +
“\005\uffe5\006\uffe5\007\uffe5\010\101\011\077\016\uffe5\020” +
“\uffe5\021\uffe5\022\uffe5\027\uffe5\001\002\000\022\004\uffc6” +
“\005\uffc6\006\uffc6\007\uffc6\016\074\020\uffc6\021\uffc6\027” +
“\uffc6\001\002\000\032\004\uffeb\005\uffeb\006\uffeb\007\uffeb” +
“\010\uffeb\011\uffeb\016\uffeb\017\066\020\uffeb\021\uffeb\022” +
“\uffeb\027\uffeb\001\002\000\020\004\uffef\005\uffef\006\uffef” +
“\007\uffef\020\uffef\021\uffef\027\uffef\001\002\000\006\022” +
“\uffd9\027\041\001\002\000\020\004\026\005\037\006\025” +
“\007\016\020\uffc8\021\ufff2\027\022\001\002\000\006\022” +
“\uffdc\027\uffdc\001\002\000\020\004\ufff0\005\ufff0\006\ufff0” +
“\007\ufff0\020\ufff0\021\ufff0\027\ufff0\001\002\000\004\024” +
“\065\001\002\000\004\022\uffd7\001\002\000\004\022\045” +
“\001\002\000\024\004\uffdf\005\uffdf\006\uffdf\007\uffdf\016” +
“\uffdf\020\uffdf\021\uffdf\022\uffd8\027\uffdf\001\002\000\010” +
“\023\uffd4\026\051\027\046\001\002\000\004\024\063\001” +
“\002\000\014\016\060\017\057\023\uffd5\026\uffc3\027\uffc3” +
“\001\002\000\014\016\uffd1\017\uffd1\023\uffd1\026\uffd1\027” +
“\uffd1\001\002\000\004\027\056\001\002\000\014\016\uffd3” +
“\017\uffd3\023\uffd3\026\uffd3\027\uffd3\001\002\000\014\016” +
“\uffd0\017\uffd0\023\uffd0\026\uffd0\027\uffd0\001\002\000\004” +
“\023\055\001\002\000\024\004\uffd6\005\uffd6\006\uffd6\007” +
“\uffd6\016\uffd6\020\uffd6\021\uffd6\022\uffd6\027\uffd6\001\002” +
“\000\014\016\uffce\017\uffce\023\uffce\026\uffce\027\uffce\001” +
“\002\000\006\026\uffc4\027\uffc4\001\002\000\006\026\uffc5” +
“\027\uffc5\001\002\000\006\026\051\027\046\001\002\000” +
“\014\016\uffd2\017\uffd2\023\uffd2\026\uffd2\027\uffd2\001\002” +
“\000\004\027\064\001\002\000\030\004\uffcf\005\uffcf\006” +
“\uffcf\007\uffcf\016\uffcf\017\uffcf\020\uffcf\021\uffcf\023\uffcf” +
“\026\uffcf\027\uffcf\001\002\000\004\022\uffda\001\002\000” +
“\004\027\067\001\002\000\034\004\uffe0\005\uffe0\006\uffe0” +
“\007\uffe0\010\uffe0\011\uffe0\016\uffe0\017\uffe0\020\uffe0\021” +
“\uffe0\022\uffe0\025\071\027\uffe0\001\002\000\032\004\uffe3” +
“\005\uffe3\006\uffe3\007\uffe3\010\uffe3\011\uffe3\016\uffe3\017” +
“\uffe3\020\uffe3\021\uffe3\022\uffe3\027\uffe3\001\002\000\004” +
“\027\073\001\002\000\032\004\uffe2\005\uffe2\006\uffe2\007” +
“\uffe2\010\uffe2\011\uffe2\016\uffe2\017\uffe2\020\uffe2\021\uffe2” +
“\022\uffe2\027\uffe2\001\002\000\032\004\uffe1\005\uffe1\006” +
“\uffe1\007\uffe1\010\uffe1\011\uffe1\016\uffe1\017\uffe1\020\uffe1” +
“\021\uffe1\022\uffe1\027\uffe1\001\002\000\020\004\uffc7\005” +
“\uffc7\006\uffc7\007\uffc7\020\uffc7\021\uffc7\027\uffc7\001\002” +
“\000\020\004\uffed\005\uffed\006\uffed\007\uffed\020\uffed\021” +
“\uffed\027\uffed\001\002\000\010\007\uffe7\020\uffe7\027\uffe7” +
“\001\002\000\010\007\uffe8\020\uffe8\027\uffe8\001\002\000” +
“\024\004\uffd7\005\uffd7\006\uffd7\007\uffd7\016\uffd7\020\uffd7” +
“\021\uffd7\022\uffd7\027\uffd7\001\002\000\010\007\uffe9\020” +
“\uffe9\027\uffe9\001\002\000\024\004\uffec\005\uffec\006\uffec” +
“\007\uffec\016\uffec\020\uffec\021\uffec\022\045\027\uffec\001” +
“\002\000\024\004\uffd8\005\uffd8\006\uffd8\007\uffd8\016\uffd8” +
“\020\uffd8\021\uffd8\022\uffd8\027\uffd8\001\002\000\010\007” +
“\016\020\uffc8\027\067\001\002\000\030\004\uffe5\005\uffe5” +
“\006\uffe5\007\uffe5\010\101\011\077\016\uffe5\020\uffe5\021” +
“\uffe5\022\uffe5\027\uffe5\001\002\000\024\004\uffe6\005\uffe6” +
“\006\uffe6\007\uffe6\016\uffe6\020\uffe6\021\uffe6\022\uffe6\027” +
“\uffe6\001\002\000\020\004\uffee\005\uffee\006\uffee\007\uffee” +
“\020\uffee\021\uffee\027\uffee\001\002\000\004\020\015\001” +
“\002\000\030\004\uffcb\005\uffcb\006\uffcb\007\uffcb\010\uffcb” +
“\011\uffcb\016\uffcb\020\uffcb\021\uffcb\022\uffcb\027\uffcb\001” +
“\002\000\032\002\ufff3\004\ufff3\005\ufff3\006\ufff3\007\ufff3” +
“\010\ufff3\011\ufff3\016\ufff3\020\ufff3\021\ufff3\022\ufff3\027” +
“\ufff3\001\002\000\004\020\uffca\001\002\000\004\002\001” +
“\001\002\000\006\020\ufff4\027\120\001\002\000\006\020” +
“\ufff6\027\ufff6\001\002\000\006\020\ufff7\027\ufff7\001\002” +
“\000\004\020\ufff5\001\002\000\004\020\ufffc\001\002\000” +
“\004\020\ufffa\001\002\000\004\020\ufffb\001\002” });
/** Access to parse-action table. */
public short[][] action_table() {return _action_table;}
/** reduce_goto
table. */
protected static final short[][] _reduce_table =
unpackFromStrings(new String[] {
“\000\121\000\010\003\005\013\010\014\011\001\001\000” +
“\004\010\122\001\001\000\004\010\121\001\001\000\004” +
“\004\114\001\001\000\002\001\001\000\002\001\001\000” +
“\002\001\001\000\004\042\012\001\001\000\004\015\013” +
“\001\001\000\002\001\001\000\034\006\034\007\023\016” +
“\020\017\035\020\033\021\027\024\031\025\030\027\032” +
“\030\022\031\026\033\017\037\016\001\001\000\002\001” +
“\001\000\002\001\001\000\002\001\001\000\002\001\001” +
“\000\004\012\071\001\001\000\002\001\001\000\004\044” +
“\107\001\001\000\002\001\001\000\002\001\001\000\002” +
“\001\001\000\004\022\106\001\001\000\006\005\077\041” +
“\075\001\001\000\004\022\074\001\001\000\002\001\001” +
“\000\002\001\001\000\004\011\041\001\001\000\030\006” +
“\034\007\023\020\037\021\027\024\031\025\030\027\032” +
“\030\022\031\026\033\017\037\016\001\001\000\002\001” +
“\001\000\002\001\001\000\002\001\001\000\006\026\042” +
“\032\043\001\001\000\002\001\001\000\002\001\001\000” +
“\014\034\053\035\046\036\051\037\047\040\052\001\001” +
“\000\002\001\001\000\004\023\060\001\001\000\002\001” +
“\001\000\002\001\001\000\002\001\001\000\002\001\001” +
“\000\002\001\001\000\002\001\001\000\002\001\001\000” +
“\002\001\001\000\002\001\001\000\010\036\061\037\047” +
“\040\052\001\001\000\002\001\001\000\002\001\001\000” +
“\002\001\001\000\002\001\001\000\004\031\067\001\001” +
“\000\004\012\071\001\001\000\002\001\001\000\002\001” +
“\001\000\002\001\001\000\002\001\001\000\002\001\001” +
“\000\002\001\001\000\004\043\103\001\001\000\002\001” +
“\001\000\006\026\101\032\102\001\001\000\002\001\001” +
“\000\002\001\001\000\002\001\001\000\014\007\023\025” +
“\104\027\032\030\022\031\026\001\001\000\006\005\105” +
“\041\075\001\001\000\002\001\001\000\002\001\001\000” +
“\004\015\110\001\001\000\002\001\001\000\002\001\001” +
“\000\002\001\001\000\002\001\001\000\004\010\120\001” +
“\001\000\002\001\001\000\002\001\001\000\002\001\001” +
“\000\002\001\001\000\002\001\001\000\002\001\001” });
/** Access to reduce_goto
table. */
public short[][] reduce_table() {return _reduce_table;}
/** Instance of action encapsulation class. */
protected CUP$Parser$actions action_obj;
/** Action encapsulation object initializer. */
protected void init_actions()
{
action_obj = new CUP$Parser$actions(this);
}
/** Invoke a user supplied parse action. */
public java_cup.runtime.Symbol do_action(
int act_num,
java_cup.runtime.lr_parser parser,
java.util.Stack stack,
int top)
throws java.lang.Exception
{
/* call code in generated class */
return action_obj.CUP$Parser$do_action(act_num, parser, stack, top);
}
/** Indicates start state. */
public int start_state() {return 0;}
/** Indicates start production. */
public int start_production() {return 0;}
/** EOF
Symbol index. */
public int EOF_sym() {return 0;}
/** error
Symbol index. */
public int error_sym() {return 1;}
/** User initialization code. */
public void user_init() throws java.lang.Exception
{
lexer.init();
action_obj.graph = theGraph;
//action_obj.parser = this;
}
/** Scan to get the next Symbol. */
public java_cup.runtime.Symbol scan()
throws java.lang.Exception
{
return lexer.next_token(debugLevel);
}
private Graph theGraph = null;
private Reader inReader;
private PrintWriter errWriter;
private Lexer lexer;
private int debugLevel = 0;
/**
* Create an instance of Parser
with input, error output and
* a supplied Graph
object. The graph object is cleared (reset) before
* new graph components are added to it by this parsing operation.
*
* @param inputReader input Reader
object
* @param errorWriter error output Writer
object (or null to suppress error output)
* @param graph Graph
object for storing parsed graph information (or null to create a new object)
*/
public Parser (Reader inputReader, PrintWriter errorWriter, Graph graph) {
super ();
inReader = inputReader;
errWriter = errorWriter;
theGraph = graph;
lexer = new Lexer (inputReader, errorWriter);
}
/**
* A convenience constructor equivalent to Parser(inputReader,errorWriter,null)
.
*
* @param inputReader input Reader
object
* @param errorWriter error output Writer
object (or null to suppress error output)
*/
public Parser (Reader inputReader, PrintWriter errorWriter) {
this(inputReader,errorWriter,null);
}
/**
* A convenience constructor equivalent to Parser(inputReader,null,null)
.
*
* @param inputReader input Reader
object
*/
public Parser (Reader inputReader) {
this(inputReader,(PrintWriter)null,null);
}
/**
* Create an instance of Parser
with input, error output and
* a supplied Graph
object. The input stream is converted to
* a Reader
and the error stream is converted to a Writer
.
*
* @param inputStream input InputStream
object
* @param errorStream error output OutputStream
object (or null to suppress error output)
* @param graph Graph
object for storing parsed graph information (or null to create a new object)
*/
public Parser (InputStream inputStream, OutputStream errorStream, Graph graph) {
this(new InputStreamReader(inputStream),new PrintWriter(errorStream,true),graph);
}
/**
* A convenience constructor equivalent to Parser(inputStream,errorStream,null)
.
*
* @param inputStream input InputStream
object
* @param errorStream error output OutputStream
object
*/
public Parser (InputStream inputStream, OutputStream errorStream) {
this(new InputStreamReader(inputStream),new PrintWriter(errorStream,true),null);
}
/**
* A convenience constructor equivalent to Parser(inputStream,null,null)
.
*
* @param inputStream input InputStream
object
*/
public Parser (InputStream inputStream) {
this(new InputStreamReader(inputStream),(PrintWriter)null,null);
}
/**
* Get the Lexer
object associated with this parser.
*
* @return the associated lexical analyzer.
*/
public Lexer getLexer() {
return lexer;
}
/**
* Get the error writer, if any, for this parser.
*
* @return the error writer for this parser.
*/
public PrintWriter getErrorWriter() {
return(errWriter);
}
/**
* Get the debug level for this parser.
* The debug level is set to a non-zero value by calling debug_parse
.
*
* @return the debug level of this parser.
* @see Parser#debug_parse(int)
*/
public int getDebugLevel() {
return(debugLevel);
}
/**
* Report a fatal error.
* Calling this method will throw a GraphParserException
.
*
* @param message the error message to send to the error stream and include in the thrown exception
* @param info not used
*
* @exception GraphParserException whenver this method is called
*/
public void report_error(String message, Object info) throws GraphParserException {
String loc = getLexer().getLocation();
if(errWriter != null) {
errWriter.println(“ERROR: Parser” + loc + “: ” + message);
}
throw new GraphParserException(“at ” + loc + “: ” + message);
}
/**
* Report a non-fatal error.
*
* @param message the warning message to send to the error stream, if the stream non-null.
* @param info not used
*/
public void report_warning(String message, Object info) {
String loc = getLexer().getLocation();
if(errWriter != null) {
errWriter.println(“WARNING: Parser” + loc + “: ” + message);
}
}
/**
* Write a debugging message to the error stream.
* The debug level of the message is 5.
*
* @param message the debug message to send to the error stream, if the stream non-null.
* @see Parser#debug_message(int,String)
*/
public void debug_message(String message) {
debug_message(5, message);
}
/**
* Write a debugging message to the error stream.
* A message is written only if the error stream is not null and the
* debug level of the message is greater than or equal to the debugging
* level of the parser.
*
* @param level the level of the message
* @param message the debug message to send to the error stream, if the stream non-null.
* @see Parser#getDebugLevel()
*/
public void debug_message(int level, String message) {
if(debugLevel < level) {
return;
}
String loc = getLexer().getLocation();
if(errWriter != null) {
errWriter.println("DEBUG: Parser" + loc + ": " + message);
}
}
/**
* Invokes the parser in debug mode.
* The lowering the debug level reduces the amount of debugging output.
* A level of 0 inhibits all debugging messages, generally a level of 10
* will let all messages get through.
*
* @param debug the debug level to use for filtering debug messages based on priority.
* @exception Exception if parse()
does
*/
public Symbol debug_parse(int debug) throws java.lang.Exception {
if(debug == 0) {
return parse();
}
debugLevel = debug;
/* the current action code */
int act;
/* the Symbol/stack element returned by a reduce */
Symbol lhs_sym = null;
/* information about production being reduced with */
short handle_size, lhs_sym_num;
/* set up direct reference to tables to drive the parser */
production_tab = production_table();
action_tab = action_table();
reduce_tab = reduce_table();
debug_message(5, “# Initializing parser”);
/* initialize the action encapsulation object */
init_actions();
/* do user initialization */
user_init();
/* the current Symbol */
cur_token = scan();
debug_message(5, “# Current Symbol is #” + cur_token.sym);
/* push dummy Symbol with start state to get us underway */
stack.push(new Symbol(0, start_state()));
tos = 0;
/* continue until we are told to stop */
for (_done_parsing = false; !_done_parsing; )
{
/* current state is always on the top of the stack */
/* look up action out of the current state with the current input */
act = get_action(((Symbol)stack.peek()).parse_state, cur_token.sym);
/* decode the action — > 0 encodes shift */
if (act > 0)
{
/* shift to the encoded state by pushing it on the stack */
cur_token.parse_state = act-1;
debug_shift(cur_token);
stack.push(cur_token);
tos++;
/* advance to the next Symbol */
cur_token = scan();
debug_message(5, “# Current token is #” + cur_token.sym);
}
/* if its less than zero, then it encodes a reduce action */
else if (act < 0)
{
/* perform the action for the reduce */
lhs_sym = do_action((-act)-1, this, stack, tos);
/* look up information about the production */
lhs_sym_num = production_tab[(-act)-1][0];
handle_size = production_tab[(-act)-1][1];
debug_reduce((-act)-1, lhs_sym_num, handle_size);
/* pop the handle off the stack */
for (int i = 0; i < handle_size; i++)
{
stack.pop();
tos--;
}
/* look up the state to go to from the one popped back to */
act = get_reduce(((Symbol)stack.peek()).parse_state, lhs_sym_num);
/* shift to that state */
lhs_sym.parse_state = act;
stack.push(lhs_sym);
tos++;
debug_message(5, "# Goto state #" + act);
}
/* finally if the entry is zero, we have an error */
else if (act == 0)
{
/* call user syntax error reporting routine */
syntax_error(cur_token);
/* try to error recover */
if (!error_recovery(true))
{
/* if that fails give up with a fatal syntax error */
unrecovered_syntax_error(cur_token);
/* just in case that wasn't fatal enough, end parse */
done_parsing();
} else {
lhs_sym = (Symbol)stack.peek();
}
}
}
return lhs_sym;
}
CUP$Parser$actions getActionObject () {
return action_obj;
}
/**
* Get the graph resulting from the parsing operations.
*
* @return the graph generated from the input.
*/
public Graph getGraph () {
return action_obj.graph;
}
}
/** Cup generated class to encapsulate user supplied action code.*/
class CUP$Parser$actions {
// a list of variables used in action code during grammar translation
//Parser parser = null;
Subgraph rootSubgraph;
Subgraph lastSubgraph;
Graph graph;
Subgraph thisGraph;
Node thisNode;
Edge thisEdge;
Node fromNode;
Node toNode;
String portName = null;
String toPortName;
String fromPortName;
int thisAttrType;
int thisElemType;
boolean directed = true;
String graphType;
private int anon_id = 0;
Vector attrs = new Vector(8,4);
Vector nodes = new Vector(8,4);
Vector edges = new Vector(8,4);
void appendAttr(String name, String value) {
attrs.addElement(new Attribute(thisElemType,name,value));
}
void noMacros() {
parser.report_error("attribute macros are not supported yet", null);
}
void attrStmt(int kind, String macroName) {
if(macroName != null) {
noMacros();
return;
}
if(attrs.size() == 0) return;
Attribute attr = null;
for(int i = 0; i < attrs.size(); i++) {
if((attr = (Attribute)(attrs.elementAt(i))).getValue() == null) {
// null means to not attach the attribute to an element
continue;
} else {
switch(kind) {
case Grappa.NODE:
parser.debug_message(1, "adding node default attr (" + attr.getName() + ") to thisGraph(" + thisGraph.getName() + ")");
thisGraph.setNodeAttribute(attr);
break;
case Grappa.EDGE:
parser.debug_message(1, "adding edge default attr (" + attr.getName() + ") to thisGraph(" + thisGraph.getName() + ")");
thisGraph.setEdgeAttribute(attr);
break;
case Grappa.SUBGRAPH:
parser.debug_message(1, "adding subg default attr (" + attr.getName() + ") to thisGraph(" + thisGraph.getName() + ")");
thisGraph.setAttribute(attr);
break;
}
}
}
attrs.removeAllElements();
}
void startGraph(String name, boolean type, boolean strict) {
if(graph == null) {
graph = new Graph(name, type, strict);
} else {
graph.reset(name, type, strict);
}
directed = type;
rootSubgraph = (Subgraph)graph;
parser.debug_message(1, "Creating top level graph (" + name + ")");
anon_id = 0;
}
void openGraph() {
thisGraph = rootSubgraph;
thisElemType = Grappa.SUBGRAPH;
parser.debug_message(1, "thisGraph(" + thisGraph.getName() + ")");
}
void closeGraph() {
int level = 1;
if(parser.getErrorWriter() != null && parser.getDebugLevel() >= level) {
parser.debug_message(level, “parsed graph follows:”);
rootSubgraph.printSubgraph(parser.getErrorWriter());
}
}
void openSubg(String name) {
thisGraph = new Subgraph(thisGraph, name);
parser.debug_message(1, “thisGraph(” + thisGraph.getName() + “)”);
thisElemType = Grappa.SUBGRAPH;
}
String anonStr() {
return Grappa.ANONYMOUS_PREFIX + anon_id++;
}
void closeSubg() {
lastSubgraph = thisGraph;
// getSubgraph() gets the parent subgraph
thisGraph = thisGraph.getSubgraph();
if(thisGraph == null) {
parser.report_error (“parser attempted to go above root Subgraph”, null);
thisGraph = rootSubgraph;
}
parser.debug_message(1, “Created subgraph (” + lastSubgraph.getName() + “) in subgraph (” + thisGraph.getName() + “)…”);
parser.debug_message(1, “thisGraph(” + thisGraph.getName() + “)”);
}
void appendNode(String name, String port) {
if((thisNode = rootSubgraph.findNodeByName(name)) == null) {
parser.debug_message(1, “Creating node in subgraph (” + thisGraph.getName() + “)…”);
thisNode = new Node(thisGraph, name);
} else {
parser.debug_message(1, “Node already in subgraph (” + thisNode.getSubgraph().getName() + “)…”);
}
Object[] pair = new Object[2];
pair[0] = thisNode;
pair[1] = port;
nodes.addElement(pair);
parser.debug_message(1, “thisNode(” + thisNode.getName() + “)”);
thisElemType = Grappa.NODE;
}
void nodeWrap() {
Object[] pair = null;
if(nodes.size() > 0 && attrs.size() > 0) {
for(int i = 0; i < nodes.size(); i++) {
pair = (Object[])(nodes.elementAt(i));
applyAttrs((Element)pair[0],null,null);
}
}
attrs.removeAllElements();
nodes.removeAllElements();
}
void bufferEdges() {
Object[] pair = new Object[2];
if(nodes.size() > 0) {
pair[0] = nodes;
nodes = new Vector(8,4);
pair[1] = new Boolean(true);
} else if(lastSubgraph != null) {
pair[0] = lastSubgraph;
lastSubgraph = null;
pair[1] = new Boolean(false);
} else {
parser.report_error (“EDGE_OP without clear antecedent nodelist or subgraph”, null);
return;
}
edges.addElement(pair);
}
void edgeWrap() {
bufferEdges();
Attribute key = null;
Attribute name = null;
Attribute attr = null;
int skip = -1;
for(int i = 0; i < attrs.size(); i++) {
attr = (Attribute)(attrs.elementAt(i));
if(attr.getName().equals("key")) {
key = attr;
if(name != null)
break;
} else if(attr.getName().equals("__nAmE__")) {
name = attr;
if(key != null)
break;
}
}
Object[] tailPair = (Object[])(edges.elementAt(0));
Object[] headPair = null;
// note: when node list is used, a non-null name will cause errors
// due to lack of uniqueness
for(int i = 1; i < edges.size(); i++) {
headPair = (Object[])(edges.elementAt(i));
if(((Boolean)(tailPair[1])).booleanValue()) { // true if node list
Vector list = (Vector)(tailPair[0]);
Object[] nodePair = null;
for(int j = 0; j < list.size(); j++) {
nodePair = (Object[])(list.elementAt(j));
edgeRHS((Node)(nodePair[0]),(String)(nodePair[1]),headPair,key,name);
}
list.removeAllElements();
} else {
Subgraph subg = (Subgraph)(tailPair[0]);
Enumeration enm = subg.elements(Grappa.NODE);
while(enm.hasMoreElements()) {
edgeRHS((Node)(enm.nextElement()),null,headPair,key,name);
}
}
tailPair = headPair;
}
edges.removeAllElements();
attrs.removeAllElements();
}
void edgeRHS(Node tail, String tailPort, Object[] headPair, Attribute keyAttr, Attribute nameAttr) {
String key = (keyAttr == null) ? null : keyAttr.getStringValue();
String name = (nameAttr == null) ? null : nameAttr.getStringValue();
if(((Boolean)(headPair[1])).booleanValue()) { // true if node list
Vector list = (Vector)(headPair[0]);
Object[] nodePair = null;
for(int j = 0; j < list.size(); j++) {
nodePair = (Object[])(list.elementAt(j));
thisEdge = new Edge(thisGraph, tail, tailPort, (Node)(nodePair[0]), (String)(nodePair[1]), key, name);
parser.debug_message(1, "Creating edge in subgraph (" + thisGraph.getName() + ")...");
parser.debug_message(1, "thisEdge(" + thisEdge.getName() + ")");
thisElemType = Grappa.EDGE;
applyAttrs((Element)thisEdge,keyAttr,nameAttr);
}
} else {
Subgraph subg = (Subgraph)(headPair[0]);
Enumeration enm = subg.elements(Grappa.NODE);
while(enm.hasMoreElements()) {
thisEdge = new Edge(thisGraph, tail, tailPort, (Node)(enm.nextElement()), null, key, name);
parser.debug_message(1, "Creating edge in subgraph (" + thisGraph.getName() + ")...");
parser.debug_message(1, "thisEdge(" + thisEdge.getName() + ")");
thisElemType = Grappa.EDGE;
applyAttrs((Element)thisEdge,keyAttr,nameAttr);
}
}
}
void applyAttrs(Element elem, Attribute skip1, Attribute skip2) {
Attribute attr = null;
for(int i = 0; i < attrs.size(); i++) {
attr = (Attribute)attrs.elementAt(i);
if(attr == skip1) continue;
else if(attr == skip2) continue;
elem.setAttribute(attr);
}
}
private final Parser parser;
/** Constructor */
CUP$Parser$actions(Parser parser) {
this.parser = parser;
}
/** Method with the actual generated action code. */
public final java_cup.runtime.Symbol CUP$Parser$do_action(
int CUP$Parser$act_num,
java_cup.runtime.lr_parser CUP$Parser$parser,
java.util.Stack CUP$Parser$stack,
int CUP$Parser$top)
throws java.lang.Exception
{
/* Symbol object for return from actions */
java_cup.runtime.Symbol CUP$Parser$result;
/* select the action based on the action number */
switch (CUP$Parser$act_num)
{
/*. . . . . . . . . . . . . . . . . . . .*/
case 62: // optSeparator ::=
{
Object RESULT = null;
CUP$Parser$result = new java_cup.runtime.Symbol(17/*optSeparator*/, ((java_cup.runtime.Symbol)CUP$Parser$stack.elementAt(CUP$Parser$top-0)).right, ((java_cup.runtime.Symbol)CUP$Parser$stack.elementAt(CUP$Parser$top-0)).right, RESULT);
}
return CUP$Parser$result;
/*. . . . . . . . . . . . . . . . . . . .*/
case 61: // optSeparator ::= COMMA
{
Object RESULT = null;
CUP$Parser$result = new java_cup.runtime.Symbol(17/*optSeparator*/, ((java_cup.runtime.Symbol)CUP$Parser$stack.elementAt(CUP$Parser$top-0)).left, ((java_cup.runtime.Symbol)CUP$Parser$stack.elementAt(CUP$Parser$top-0)).right, RESULT);
}
return CUP$Parser$result;
/*. . . . . . . . . . . . . . . . . . . .*/
case 60: // optSeparator ::= SEMI
{
Object RESULT = null;
CUP$Parser$result = new java_cup.runtime.Symbol(17/*optSeparator*/, ((java_cup.runtime.Symbol)CUP$Parser$stack.elementAt(CUP$Parser$top-0)).left, ((java_cup.runtime.Symbol)CUP$Parser$stack.elementAt(CUP$Parser$top-0)).right, RESULT);
}
return CUP$Parser$result;
/*. . . . . . . . . . . . . . . . . . . .*/
case 59: // optSemi ::=
{
Object RESULT = null;
CUP$Parser$result = new java_cup.runtime.Symbol(16/*optSemi*/, ((java_cup.runtime.Symbol)CUP$Parser$stack.elementAt(CUP$Parser$top-0)).right, ((java_cup.runtime.Symbol)CUP$Parser$stack.elementAt(CUP$Parser$top-0)).right, RESULT);
}
return CUP$Parser$result;
/*. . . . . . . . . . . . . . . . . . . .*/
case 58: // optSemi ::= SEMI
{
Object RESULT = null;
CUP$Parser$result = new java_cup.runtime.Symbol(16/*optSemi*/, ((java_cup.runtime.Symbol)CUP$Parser$stack.elementAt(CUP$Parser$top-0)).left, ((java_cup.runtime.Symbol)CUP$Parser$stack.elementAt(CUP$Parser$top-0)).right, RESULT);
}
return CUP$Parser$result;
/*. . . . . . . . . . . . . . . . . . . .*/
case 57: // optSubgHdr ::=
{
String RESULT = null;
RESULT = anonStr();
CUP$Parser$result = new java_cup.runtime.Symbol(5/*optSubgHdr*/, ((java_cup.runtime.Symbol)CUP$Parser$stack.elementAt(CUP$Parser$top-0)).right, ((java_cup.runtime.Symbol)CUP$Parser$stack.elementAt(CUP$Parser$top-0)).right, RESULT);
}
return CUP$Parser$result;
/*. . . . . . . . . . . . . . . . . . . .*/
case 56: // optSubgHdr ::= SUBGRAPH
{
String RESULT = null;
RESULT = anonStr();
CUP$Parser$result = new java_cup.runtime.Symbol(5/*optSubgHdr*/, ((java_cup.runtime.Symbol)CUP$Parser$stack.elementAt(CUP$Parser$top-0)).left, ((java_cup.runtime.Symbol)CUP$Parser$stack.elementAt(CUP$Parser$top-0)).right, RESULT);
}
return CUP$Parser$result;
/*. . . . . . . . . . . . . . . . . . . .*/
case 55: // optSubgHdr ::= SUBGRAPH ATOM
{
String RESULT = null;
int valleft = ((java_cup.runtime.Symbol)CUP$Parser$stack.elementAt(CUP$Parser$top-0)).left;
int valright = ((java_cup.runtime.Symbol)CUP$Parser$stack.elementAt(CUP$Parser$top-0)).right;
String val = (String)((java_cup.runtime.Symbol) CUP$Parser$stack.elementAt(CUP$Parser$top-0)).value;
RESULT = val;
CUP$Parser$result = new java_cup.runtime.Symbol(5/*optSubgHdr*/, ((java_cup.runtime.Symbol)CUP$Parser$stack.elementAt(CUP$Parser$top-1)).left, ((java_cup.runtime.Symbol)CUP$Parser$stack.elementAt(CUP$Parser$top-0)).right, RESULT);
}
return CUP$Parser$result;
/*. . . . . . . . . . . . . . . . . . . .*/
case 54: // subgraph ::= optSubgHdr NT$2 body
{
Object RESULT = null;
// propagate RESULT from NT$2
if ( ((java_cup.runtime.Symbol) CUP$Parser$stack.elementAt(CUP$Parser$top-1)).value != null )
RESULT = (Object) ((java_cup.runtime.Symbol) CUP$Parser$stack.elementAt(CUP$Parser$top-1)).value;
int valleft = ((java_cup.runtime.Symbol)CUP$Parser$stack.elementAt(CUP$Parser$top-2)).left;
int valright = ((java_cup.runtime.Symbol)CUP$Parser$stack.elementAt(CUP$Parser$top-2)).right;
String val = (String)((java_cup.runtime.Symbol) CUP$Parser$stack.elementAt(CUP$Parser$top-2)).value;
closeSubg();
CUP$Parser$result = new java_cup.runtime.Symbol(22/*subgraph*/, ((java_cup.runtime.Symbol)CUP$Parser$stack.elementAt(CUP$Parser$top-2)).left, ((java_cup.runtime.Symbol)CUP$Parser$stack.elementAt(CUP$Parser$top-0)).right, RESULT);
}
return CUP$Parser$result;
/*. . . . . . . . . . . . . . . . . . . .*/
case 53: // NT$2 ::=
{
Object RESULT = null;
int valleft = ((java_cup.runtime.Symbol)CUP$Parser$stack.elementAt(CUP$Parser$top-0)).left;
int valright = ((java_cup.runtime.Symbol)CUP$Parser$stack.elementAt(CUP$Parser$top-0)).right;
String val = (String)((java_cup.runtime.Symbol) CUP$Parser$stack.elementAt(CUP$Parser$top-0)).value;
openSubg(val);
CUP$Parser$result = new java_cup.runtime.Symbol(34/*NT$2*/, ((java_cup.runtime.Symbol)CUP$Parser$stack.elementAt(CUP$Parser$top-0)).right, ((java_cup.runtime.Symbol)CUP$Parser$stack.elementAt(CUP$Parser$top-0)).right, RESULT);
}
return CUP$Parser$result;
/*. . . . . . . . . . . . . . . . . . . .*/
case 52: // graphAttrDefs ::= attrAssignment
{
Object RESULT = null;
CUP$Parser$result = new java_cup.runtime.Symbol(25/*graphAttrDefs*/, ((java_cup.runtime.Symbol)CUP$Parser$stack.elementAt(CUP$Parser$top-0)).left, ((java_cup.runtime.Symbol)CUP$Parser$stack.elementAt(CUP$Parser$top-0)).right, RESULT);
}
return CUP$Parser$result;
/*. . . . . . . . . . . . . . . . . . . .*/
case 51: // attrMacro ::= ATSIGN ATOM
{
Object RESULT = null;
int nameleft = ((java_cup.runtime.Symbol)CUP$Parser$stack.elementAt(CUP$Parser$top-0)).left;
int nameright = ((java_cup.runtime.Symbol)CUP$Parser$stack.elementAt(CUP$Parser$top-0)).right;
String name = (String)((java_cup.runtime.Symbol) CUP$Parser$stack.elementAt(CUP$Parser$top-0)).value;
appendAttr(name,null);
CUP$Parser$result = new java_cup.runtime.Symbol(30/*attrMacro*/, ((java_cup.runtime.Symbol)CUP$Parser$stack.elementAt(CUP$Parser$top-1)).left, ((java_cup.runtime.Symbol)CUP$Parser$stack.elementAt(CUP$Parser$top-0)).right, RESULT);
}
return CUP$Parser$result;
/*. . . . . . . . . . . . . . . . . . . .*/
case 50: // attrAssignment ::= ATOM EQUAL ATOM
{
Object RESULT = null;
int nameleft = ((java_cup.runtime.Symbol)CUP$Parser$stack.elementAt(CUP$Parser$top-2)).left;
int nameright = ((java_cup.runtime.Symbol)CUP$Parser$stack.elementAt(CUP$Parser$top-2)).right;
String name = (String)((java_cup.runtime.Symbol) CUP$Parser$stack.elementAt(CUP$Parser$top-2)).value;
int valueleft = ((java_cup.runtime.Symbol)CUP$Parser$stack.elementAt(CUP$Parser$top-0)).left;
int valueright = ((java_cup.runtime.Symbol)CUP$Parser$stack.elementAt(CUP$Parser$top-0)).right;
String value = (String)((java_cup.runtime.Symbol) CUP$Parser$stack.elementAt(CUP$Parser$top-0)).value;
appendAttr(name,value);
CUP$Parser$result = new java_cup.runtime.Symbol(29/*attrAssignment*/, ((java_cup.runtime.Symbol)CUP$Parser$stack.elementAt(CUP$Parser$top-2)).left, ((java_cup.runtime.Symbol)CUP$Parser$stack.elementAt(CUP$Parser$top-0)).right, RESULT);
}
return CUP$Parser$result;
/*. . . . . . . . . . . . . . . . . . . .*/
case 49: // attrItem ::= attrMacro
{
Object RESULT = null;
CUP$Parser$result = new java_cup.runtime.Symbol(28/*attrItem*/, ((java_cup.runtime.Symbol)CUP$Parser$stack.elementAt(CUP$Parser$top-0)).left, ((java_cup.runtime.Symbol)CUP$Parser$stack.elementAt(CUP$Parser$top-0)).right, RESULT);
}
return CUP$Parser$result;
/*. . . . . . . . . . . . . . . . . . . .*/
case 48: // attrItem ::= attrAssignment
{
Object RESULT = null;
CUP$Parser$result = new java_cup.runtime.Symbol(28/*attrItem*/, ((java_cup.runtime.Symbol)CUP$Parser$stack.elementAt(CUP$Parser$top-0)).left, ((java_cup.runtime.Symbol)CUP$Parser$stack.elementAt(CUP$Parser$top-0)).right, RESULT);
}
return CUP$Parser$result;
/*. . . . . . . . . . . . . . . . . . . .*/
case 47: // attrDefs ::= attrDefs optSeparator attrItem
{
Object RESULT = null;
CUP$Parser$result = new java_cup.runtime.Symbol(27/*attrDefs*/, ((java_cup.runtime.Symbol)CUP$Parser$stack.elementAt(CUP$Parser$top-2)).left, ((java_cup.runtime.Symbol)CUP$Parser$stack.elementAt(CUP$Parser$top-0)).right, RESULT);
}
return CUP$Parser$result;
/*. . . . . . . . . . . . . . . . . . . .*/
case 46: // attrDefs ::= attrItem
{
Object RESULT = null;
CUP$Parser$result = new java_cup.runtime.Symbol(27/*attrDefs*/, ((java_cup.runtime.Symbol)CUP$Parser$stack.elementAt(CUP$Parser$top-0)).left, ((java_cup.runtime.Symbol)CUP$Parser$stack.elementAt(CUP$Parser$top-0)).right, RESULT);
}
return CUP$Parser$result;
/*. . . . . . . . . . . . . . . . . . . .*/
case 45: // optAttrDefs ::=
{
Object RESULT = null;
CUP$Parser$result = new java_cup.runtime.Symbol(26/*optAttrDefs*/, ((java_cup.runtime.Symbol)CUP$Parser$stack.elementAt(CUP$Parser$top-0)).right, ((java_cup.runtime.Symbol)CUP$Parser$stack.elementAt(CUP$Parser$top-0)).right, RESULT);
}
return CUP$Parser$result;
/*. . . . . . . . . . . . . . . . . . . .*/
case 44: // optAttrDefs ::= attrDefs
{
Object RESULT = null;
CUP$Parser$result = new java_cup.runtime.Symbol(26/*optAttrDefs*/, ((java_cup.runtime.Symbol)CUP$Parser$stack.elementAt(CUP$Parser$top-0)).left, ((java_cup.runtime.Symbol)CUP$Parser$stack.elementAt(CUP$Parser$top-0)).right, RESULT);
}
return CUP$Parser$result;
/*. . . . . . . . . . . . . . . . . . . .*/
case 43: // attrList ::= optAttr LBR optAttrDefs RBR
{
Object RESULT = null;
CUP$Parser$result = new java_cup.runtime.Symbol(24/*attrList*/, ((java_cup.runtime.Symbol)CUP$Parser$stack.elementAt(CUP$Parser$top-3)).left, ((java_cup.runtime.Symbol)CUP$Parser$stack.elementAt(CUP$Parser$top-0)).right, RESULT);
}
return CUP$Parser$result;
/*. . . . . . . . . . . . . . . . . . . .*/
case 42: // optAttr ::=
{
Object RESULT = null;
CUP$Parser$result = new java_cup.runtime.Symbol(20/*optAttr*/, ((java_cup.runtime.Symbol)CUP$Parser$stack.elementAt(CUP$Parser$top-0)).right, ((java_cup.runtime.Symbol)CUP$Parser$stack.elementAt(CUP$Parser$top-0)).right, RESULT);
}
return CUP$Parser$result;
/*. . . . . . . . . . . . . . . . . . . .*/
case 41: // optAttr ::= attrList
{
Object RESULT = null;
CUP$Parser$result = new java_cup.runtime.Symbol(20/*optAttr*/, ((java_cup.runtime.Symbol)CUP$Parser$stack.elementAt(CUP$Parser$top-0)).left, ((java_cup.runtime.Symbol)CUP$Parser$stack.elementAt(CUP$Parser$top-0)).right, RESULT);
}
return CUP$Parser$result;
/*. . . . . . . . . . . . . . . . . . . .*/
case 40: // optMacroName ::=
{
String RESULT = null;
RESULT = null;
CUP$Parser$result = new java_cup.runtime.Symbol(7/*optMacroName*/, ((java_cup.runtime.Symbol)CUP$Parser$stack.elementAt(CUP$Parser$top-0)).right, ((java_cup.runtime.Symbol)CUP$Parser$stack.elementAt(CUP$Parser$top-0)).right, RESULT);
}
return CUP$Parser$result;
/*. . . . . . . . . . . . . . . . . . . .*/
case 39: // optMacroName ::= ATOM EQUAL
{
String RESULT = null;
int valleft = ((java_cup.runtime.Symbol)CUP$Parser$stack.elementAt(CUP$Parser$top-1)).left;
int valright = ((java_cup.runtime.Symbol)CUP$Parser$stack.elementAt(CUP$Parser$top-1)).right;
String val = (String)((java_cup.runtime.Symbol) CUP$Parser$stack.elementAt(CUP$Parser$top-1)).value;
RESULT = val;
CUP$Parser$result = new java_cup.runtime.Symbol(7/*optMacroName*/, ((java_cup.runtime.Symbol)CUP$Parser$stack.elementAt(CUP$Parser$top-1)).left, ((java_cup.runtime.Symbol)CUP$Parser$stack.elementAt(CUP$Parser$top-0)).right, RESULT);
}
return CUP$Parser$result;
/*. . . . . . . . . . . . . . . . . . . .*/
case 38: // attrType ::= EDGE
{
Integer RESULT = null;
int valleft = ((java_cup.runtime.Symbol)CUP$Parser$stack.elementAt(CUP$Parser$top-0)).left;
int valright = ((java_cup.runtime.Symbol)CUP$Parser$stack.elementAt(CUP$Parser$top-0)).right;
Integer val = (Integer)((java_cup.runtime.Symbol) CUP$Parser$stack.elementAt(CUP$Parser$top-0)).value;
RESULT = new Integer(Grappa.EDGE);
CUP$Parser$result = new java_cup.runtime.Symbol(4/*attrType*/, ((java_cup.runtime.Symbol)CUP$Parser$stack.elementAt(CUP$Parser$top-0)).left, ((java_cup.runtime.Symbol)CUP$Parser$stack.elementAt(CUP$Parser$top-0)).right, RESULT);
}
return CUP$Parser$result;
/*. . . . . . . . . . . . . . . . . . . .*/
case 37: // attrType ::= NODE
{
Integer RESULT = null;
int valleft = ((java_cup.runtime.Symbol)CUP$Parser$stack.elementAt(CUP$Parser$top-0)).left;
int valright = ((java_cup.runtime.Symbol)CUP$Parser$stack.elementAt(CUP$Parser$top-0)).right;
Integer val = (Integer)((java_cup.runtime.Symbol) CUP$Parser$stack.elementAt(CUP$Parser$top-0)).value;
RESULT = new Integer(Grappa.NODE);
CUP$Parser$result = new java_cup.runtime.Symbol(4/*attrType*/, ((java_cup.runtime.Symbol)CUP$Parser$stack.elementAt(CUP$Parser$top-0)).left, ((java_cup.runtime.Symbol)CUP$Parser$stack.elementAt(CUP$Parser$top-0)).right, RESULT);
}
return CUP$Parser$result;
/*. . . . . . . . . . . . . . . . . . . .*/
case 36: // attrType ::= GRAPH
{
Integer RESULT = null;
int valleft = ((java_cup.runtime.Symbol)CUP$Parser$stack.elementAt(CUP$Parser$top-0)).left;
int valright = ((java_cup.runtime.Symbol)CUP$Parser$stack.elementAt(CUP$Parser$top-0)).right;
Integer val = (Integer)((java_cup.runtime.Symbol) CUP$Parser$stack.elementAt(CUP$Parser$top-0)).value;
RESULT = new Integer(Grappa.SUBGRAPH);
CUP$Parser$result = new java_cup.runtime.Symbol(4/*attrType*/, ((java_cup.runtime.Symbol)CUP$Parser$stack.elementAt(CUP$Parser$top-0)).left, ((java_cup.runtime.Symbol)CUP$Parser$stack.elementAt(CUP$Parser$top-0)).right, RESULT);
}
return CUP$Parser$result;
/*. . . . . . . . . . . . . . . . . . . .*/
case 35: // attrStmt ::= graphAttrDefs
{
Object RESULT = null;
attrStmt(Grappa.SUBGRAPH,null);
CUP$Parser$result = new java_cup.runtime.Symbol(15/*attrStmt*/, ((java_cup.runtime.Symbol)CUP$Parser$stack.elementAt(CUP$Parser$top-0)).left, ((java_cup.runtime.Symbol)CUP$Parser$stack.elementAt(CUP$Parser$top-0)).right, RESULT);
}
return CUP$Parser$result;
/*. . . . . . . . . . . . . . . . . . . .*/
case 34: // attrStmt ::= attrType optMacroName attrList
{
Object RESULT = null;
int typeleft = ((java_cup.runtime.Symbol)CUP$Parser$stack.elementAt(CUP$Parser$top-2)).left;
int typeright = ((java_cup.runtime.Symbol)CUP$Parser$stack.elementAt(CUP$Parser$top-2)).right;
Integer type = (Integer)((java_cup.runtime.Symbol) CUP$Parser$stack.elementAt(CUP$Parser$top-2)).value;
int nameleft = ((java_cup.runtime.Symbol)CUP$Parser$stack.elementAt(CUP$Parser$top-1)).left;
int nameright = ((java_cup.runtime.Symbol)CUP$Parser$stack.elementAt(CUP$Parser$top-1)).right;
String name = (String)((java_cup.runtime.Symbol) CUP$Parser$stack.elementAt(CUP$Parser$top-1)).value;
attrStmt(type.intValue(),name);
CUP$Parser$result = new java_cup.runtime.Symbol(15/*attrStmt*/, ((java_cup.runtime.Symbol)CUP$Parser$stack.elementAt(CUP$Parser$top-2)).left, ((java_cup.runtime.Symbol)CUP$Parser$stack.elementAt(CUP$Parser$top-0)).right, RESULT);
}
return CUP$Parser$result;
/*. . . . . . . . . . . . . . . . . . . .*/
case 33: // optPort ::=
{
String RESULT = null;
RESULT = null;
CUP$Parser$result = new java_cup.runtime.Symbol(8/*optPort*/, ((java_cup.runtime.Symbol)CUP$Parser$stack.elementAt(CUP$Parser$top-0)).right, ((java_cup.runtime.Symbol)CUP$Parser$stack.elementAt(CUP$Parser$top-0)).right, RESULT);
}
return CUP$Parser$result;
/*. . . . . . . . . . . . . . . . . . . .*/
case 32: // optPort ::= COLON ATOM
{
String RESULT = null;
int valleft = ((java_cup.runtime.Symbol)CUP$Parser$stack.elementAt(CUP$Parser$top-0)).left;
int valright = ((java_cup.runtime.Symbol)CUP$Parser$stack.elementAt(CUP$Parser$top-0)).right;
String val = (String)((java_cup.runtime.Symbol) CUP$Parser$stack.elementAt(CUP$Parser$top-0)).value;
RESULT = val;
CUP$Parser$result = new java_cup.runtime.Symbol(8/*optPort*/, ((java_cup.runtime.Symbol)CUP$Parser$stack.elementAt(CUP$Parser$top-1)).left, ((java_cup.runtime.Symbol)CUP$Parser$stack.elementAt(CUP$Parser$top-0)).right, RESULT);
}
return CUP$Parser$result;
/*. . . . . . . . . . . . . . . . . . . .*/
case 31: // node ::= ATOM optPort
{
Object RESULT = null;
int nameleft = ((java_cup.runtime.Symbol)CUP$Parser$stack.elementAt(CUP$Parser$top-1)).left;
int nameright = ((java_cup.runtime.Symbol)CUP$Parser$stack.elementAt(CUP$Parser$top-1)).right;
String name = (String)((java_cup.runtime.Symbol) CUP$Parser$stack.elementAt(CUP$Parser$top-1)).value;
int portleft = ((java_cup.runtime.Symbol)CUP$Parser$stack.elementAt(CUP$Parser$top-0)).left;
int portright = ((java_cup.runtime.Symbol)CUP$Parser$stack.elementAt(CUP$Parser$top-0)).right;
String port = (String)((java_cup.runtime.Symbol) CUP$Parser$stack.elementAt(CUP$Parser$top-0)).value;
appendNode(name,port);
CUP$Parser$result = new java_cup.runtime.Symbol(23/*node*/, ((java_cup.runtime.Symbol)CUP$Parser$stack.elementAt(CUP$Parser$top-1)).left, ((java_cup.runtime.Symbol)CUP$Parser$stack.elementAt(CUP$Parser$top-0)).right, RESULT);
}
return CUP$Parser$result;
/*. . . . . . . . . . . . . . . . . . . .*/
case 30: // nodeList ::= nodeList COMMA node
{
Object RESULT = null;
CUP$Parser$result = new java_cup.runtime.Symbol(21/*nodeList*/, ((java_cup.runtime.Symbol)CUP$Parser$stack.elementAt(CUP$Parser$top-2)).left, ((java_cup.runtime.Symbol)CUP$Parser$stack.elementAt(CUP$Parser$top-0)).right, RESULT);
}
return CUP$Parser$result;
/*. . . . . . . . . . . . . . . . . . . .*/
case 29: // nodeList ::= node
{
Object RESULT = null;
CUP$Parser$result = new java_cup.runtime.Symbol(21/*nodeList*/, ((java_cup.runtime.Symbol)CUP$Parser$stack.elementAt(CUP$Parser$top-0)).left, ((java_cup.runtime.Symbol)CUP$Parser$stack.elementAt(CUP$Parser$top-0)).right, RESULT);
}
return CUP$Parser$result;
/*. . . . . . . . . . . . . . . . . . . .*/
case 28: // rCompound ::=
{
Boolean RESULT = null;
thisElemType = Grappa.NODE;
RESULT = new Boolean(false);
CUP$Parser$result = new java_cup.runtime.Symbol(3/*rCompound*/, ((java_cup.runtime.Symbol)CUP$Parser$stack.elementAt(CUP$Parser$top-0)).right, ((java_cup.runtime.Symbol)CUP$Parser$stack.elementAt(CUP$Parser$top-0)).right, RESULT);
}
return CUP$Parser$result;
/*. . . . . . . . . . . . . . . . . . . .*/
case 27: // rCompound ::= edge_op NT$1 simple rCompound
{
Boolean RESULT = null;
// propagate RESULT from NT$1
if ( ((java_cup.runtime.Symbol) CUP$Parser$stack.elementAt(CUP$Parser$top-2)).value != null )
RESULT = (Boolean) ((java_cup.runtime.Symbol) CUP$Parser$stack.elementAt(CUP$Parser$top-2)).value;
int valleft = ((java_cup.runtime.Symbol)CUP$Parser$stack.elementAt(CUP$Parser$top-0)).left;
int valright = ((java_cup.runtime.Symbol)CUP$Parser$stack.elementAt(CUP$Parser$top-0)).right;
Boolean val = (Boolean)((java_cup.runtime.Symbol) CUP$Parser$stack.elementAt(CUP$Parser$top-0)).value;
thisElemType = Grappa.EDGE;
RESULT = new Boolean(true);
CUP$Parser$result = new java_cup.runtime.Symbol(3/*rCompound*/, ((java_cup.runtime.Symbol)CUP$Parser$stack.elementAt(CUP$Parser$top-3)).left, ((java_cup.runtime.Symbol)CUP$Parser$stack.elementAt(CUP$Parser$top-0)).right, RESULT);
}
return CUP$Parser$result;
/*. . . . . . . . . . . . . . . . . . . .*/
case 26: // NT$1 ::=
{
Object RESULT = null;
thisElemType = Grappa.EDGE;
bufferEdges();
CUP$Parser$result = new java_cup.runtime.Symbol(33/*NT$1*/, ((java_cup.runtime.Symbol)CUP$Parser$stack.elementAt(CUP$Parser$top-0)).right, ((java_cup.runtime.Symbol)CUP$Parser$stack.elementAt(CUP$Parser$top-0)).right, RESULT);
}
return CUP$Parser$result;
/*. . . . . . . . . . . . . . . . . . . .*/
case 25: // edge_op ::= ND_EDGE_OP
{
Object RESULT = null;
if(directed) {
//CUP$parser.report_error ("attempt to create a non-directed edge in a directed graph",null);
parser.report_error ("attempt to create a non-directed edge in a directed graph",null);
}
CUP$Parser$result = new java_cup.runtime.Symbol(31/*edge_op*/, ((java_cup.runtime.Symbol)CUP$Parser$stack.elementAt(CUP$Parser$top-0)).left, ((java_cup.runtime.Symbol)CUP$Parser$stack.elementAt(CUP$Parser$top-0)).right, RESULT);
}
return CUP$Parser$result;
/*. . . . . . . . . . . . . . . . . . . .*/
case 24: // edge_op ::= D_EDGE_OP
{
Object RESULT = null;
if(!directed) {
//CUP$parser.report_error ("attempt to create a directed edge in a non-directed graph",null);
parser.report_error ("attempt to create a directed edge in a non-directed graph",null);
}
CUP$Parser$result = new java_cup.runtime.Symbol(31/*edge_op*/, ((java_cup.runtime.Symbol)CUP$Parser$stack.elementAt(CUP$Parser$top-0)).left, ((java_cup.runtime.Symbol)CUP$Parser$stack.elementAt(CUP$Parser$top-0)).right, RESULT);
}
return CUP$Parser$result;
/*. . . . . . . . . . . . . . . . . . . .*/
case 23: // simple ::= subgraph
{
Object RESULT = null;
CUP$Parser$result = new java_cup.runtime.Symbol(19/*simple*/, ((java_cup.runtime.Symbol)CUP$Parser$stack.elementAt(CUP$Parser$top-0)).left, ((java_cup.runtime.Symbol)CUP$Parser$stack.elementAt(CUP$Parser$top-0)).right, RESULT);
}
return CUP$Parser$result;
/*. . . . . . . . . . . . . . . . . . . .*/
case 22: // simple ::= nodeList
{
Object RESULT = null;
CUP$Parser$result = new java_cup.runtime.Symbol(19/*simple*/, ((java_cup.runtime.Symbol)CUP$Parser$stack.elementAt(CUP$Parser$top-0)).left, ((java_cup.runtime.Symbol)CUP$Parser$stack.elementAt(CUP$Parser$top-0)).right, RESULT);
}
return CUP$Parser$result;
/*. . . . . . . . . . . . . . . . . . . .*/
case 21: // compound ::= simple rCompound optAttr
{
Object RESULT = null;
int valleft = ((java_cup.runtime.Symbol)CUP$Parser$stack.elementAt(CUP$Parser$top-1)).left;
int valright = ((java_cup.runtime.Symbol)CUP$Parser$stack.elementAt(CUP$Parser$top-1)).right;
Boolean val = (Boolean)((java_cup.runtime.Symbol) CUP$Parser$stack.elementAt(CUP$Parser$top-1)).value;
if (val.booleanValue()) edgeWrap();
else nodeWrap();
CUP$Parser$result = new java_cup.runtime.Symbol(18/*compound*/, ((java_cup.runtime.Symbol)CUP$Parser$stack.elementAt(CUP$Parser$top-2)).left, ((java_cup.runtime.Symbol)CUP$Parser$stack.elementAt(CUP$Parser$top-0)).right, RESULT);
}
return CUP$Parser$result;
/*. . . . . . . . . . . . . . . . . . . .*/
case 20: // stmt ::= compound optSemi
{
Object RESULT = null;
CUP$Parser$result = new java_cup.runtime.Symbol(14/*stmt*/, ((java_cup.runtime.Symbol)CUP$Parser$stack.elementAt(CUP$Parser$top-1)).left, ((java_cup.runtime.Symbol)CUP$Parser$stack.elementAt(CUP$Parser$top-0)).right, RESULT);
}
return CUP$Parser$result;
/*. . . . . . . . . . . . . . . . . . . .*/
case 19: // stmt ::= attrStmt optSemi
{
Object RESULT = null;
CUP$Parser$result = new java_cup.runtime.Symbol(14/*stmt*/, ((java_cup.runtime.Symbol)CUP$Parser$stack.elementAt(CUP$Parser$top-1)).left, ((java_cup.runtime.Symbol)CUP$Parser$stack.elementAt(CUP$Parser$top-0)).right, RESULT);
}
return CUP$Parser$result;
/*. . . . . . . . . . . . . . . . . . . .*/
case 18: // stmtList ::= stmt
{
Object RESULT = null;
CUP$Parser$result = new java_cup.runtime.Symbol(13/*stmtList*/, ((java_cup.runtime.Symbol)CUP$Parser$stack.elementAt(CUP$Parser$top-0)).left, ((java_cup.runtime.Symbol)CUP$Parser$stack.elementAt(CUP$Parser$top-0)).right, RESULT);
}
return CUP$Parser$result;
/*. . . . . . . . . . . . . . . . . . . .*/
case 17: // stmtList ::= stmtList stmt
{
Object RESULT = null;
CUP$Parser$result = new java_cup.runtime.Symbol(13/*stmtList*/, ((java_cup.runtime.Symbol)CUP$Parser$stack.elementAt(CUP$Parser$top-1)).left, ((java_cup.runtime.Symbol)CUP$Parser$stack.elementAt(CUP$Parser$top-0)).right, RESULT);
}
return CUP$Parser$result;
/*. . . . . . . . . . . . . . . . . . . .*/
case 16: // optStmtList ::=
{
Object RESULT = null;
CUP$Parser$result = new java_cup.runtime.Symbol(12/*optStmtList*/, ((java_cup.runtime.Symbol)CUP$Parser$stack.elementAt(CUP$Parser$top-0)).right, ((java_cup.runtime.Symbol)CUP$Parser$stack.elementAt(CUP$Parser$top-0)).right, RESULT);
}
return CUP$Parser$result;
/*. . . . . . . . . . . . . . . . . . . .*/
case 15: // optStmtList ::= stmtList
{
Object RESULT = null;
CUP$Parser$result = new java_cup.runtime.Symbol(12/*optStmtList*/, ((java_cup.runtime.Symbol)CUP$Parser$stack.elementAt(CUP$Parser$top-0)).left, ((java_cup.runtime.Symbol)CUP$Parser$stack.elementAt(CUP$Parser$top-0)).right, RESULT);
}
return CUP$Parser$result;
/*. . . . . . . . . . . . . . . . . . . .*/
case 14: // body ::= LCUR optStmtList RCUR
{
Object RESULT = null;
CUP$Parser$result = new java_cup.runtime.Symbol(11/*body*/, ((java_cup.runtime.Symbol)CUP$Parser$stack.elementAt(CUP$Parser$top-2)).left, ((java_cup.runtime.Symbol)CUP$Parser$stack.elementAt(CUP$Parser$top-0)).right, RESULT);
}
return CUP$Parser$result;
/*. . . . . . . . . . . . . . . . . . . .*/
case 13: // optGraphName ::=
{
String RESULT = null;
RESULT = anonStr();
CUP$Parser$result = new java_cup.runtime.Symbol(6/*optGraphName*/, ((java_cup.runtime.Symbol)CUP$Parser$stack.elementAt(CUP$Parser$top-0)).right, ((java_cup.runtime.Symbol)CUP$Parser$stack.elementAt(CUP$Parser$top-0)).right, RESULT);
}
return CUP$Parser$result;
/*. . . . . . . . . . . . . . . . . . . .*/
case 12: // optGraphName ::= ATOM
{
String RESULT = null;
int valleft = ((java_cup.runtime.Symbol)CUP$Parser$stack.elementAt(CUP$Parser$top-0)).left;
int valright = ((java_cup.runtime.Symbol)CUP$Parser$stack.elementAt(CUP$Parser$top-0)).right;
String val = (String)((java_cup.runtime.Symbol) CUP$Parser$stack.elementAt(CUP$Parser$top-0)).value;
RESULT = val;
CUP$Parser$result = new java_cup.runtime.Symbol(6/*optGraphName*/, ((java_cup.runtime.Symbol)CUP$Parser$stack.elementAt(CUP$Parser$top-0)).left, ((java_cup.runtime.Symbol)CUP$Parser$stack.elementAt(CUP$Parser$top-0)).right, RESULT);
}
return CUP$Parser$result;
/*. . . . . . . . . . . . . . . . . . . .*/
case 11: // graphType ::= DIGRAPH
{
Boolean RESULT = null;
RESULT = new Boolean(true);
CUP$Parser$result = new java_cup.runtime.Symbol(2/*graphType*/, ((java_cup.runtime.Symbol)CUP$Parser$stack.elementAt(CUP$Parser$top-0)).left, ((java_cup.runtime.Symbol)CUP$Parser$stack.elementAt(CUP$Parser$top-0)).right, RESULT);
}
return CUP$Parser$result;
/*. . . . . . . . . . . . . . . . . . . .*/
case 10: // graphType ::= GRAPH
{
Boolean RESULT = null;
RESULT = new Boolean(false);
CUP$Parser$result = new java_cup.runtime.Symbol(2/*graphType*/, ((java_cup.runtime.Symbol)CUP$Parser$stack.elementAt(CUP$Parser$top-0)).left, ((java_cup.runtime.Symbol)CUP$Parser$stack.elementAt(CUP$Parser$top-0)).right, RESULT);
}
return CUP$Parser$result;
/*. . . . . . . . . . . . . . . . . . . .*/
case 9: // optStrict ::=
{
Boolean RESULT = null;
RESULT = new Boolean(false);
CUP$Parser$result = new java_cup.runtime.Symbol(1/*optStrict*/, ((java_cup.runtime.Symbol)CUP$Parser$stack.elementAt(CUP$Parser$top-0)).right, ((java_cup.runtime.Symbol)CUP$Parser$stack.elementAt(CUP$Parser$top-0)).right, RESULT);
}
return CUP$Parser$result;
/*. . . . . . . . . . . . . . . . . . . .*/
case 8: // optStrict ::= STRICT
{
Boolean RESULT = null;
RESULT = new Boolean(true);
CUP$Parser$result = new java_cup.runtime.Symbol(1/*optStrict*/, ((java_cup.runtime.Symbol)CUP$Parser$stack.elementAt(CUP$Parser$top-0)).left, ((java_cup.runtime.Symbol)CUP$Parser$stack.elementAt(CUP$Parser$top-0)).right, RESULT);
}
return CUP$Parser$result;
/*. . . . . . . . . . . . . . . . . . . .*/
case 7: // hdr ::= STRICTDIGRAPH optGraphName
{
Object RESULT = null;
int nameleft = ((java_cup.runtime.Symbol)CUP$Parser$stack.elementAt(CUP$Parser$top-0)).left;
int nameright = ((java_cup.runtime.Symbol)CUP$Parser$stack.elementAt(CUP$Parser$top-0)).right;
String name = (String)((java_cup.runtime.Symbol) CUP$Parser$stack.elementAt(CUP$Parser$top-0)).value;
startGraph(name,true,true);
CUP$Parser$result = new java_cup.runtime.Symbol(10/*hdr*/, ((java_cup.runtime.Symbol)CUP$Parser$stack.elementAt(CUP$Parser$top-1)).left, ((java_cup.runtime.Symbol)CUP$Parser$stack.elementAt(CUP$Parser$top-0)).right, RESULT);
}
return CUP$Parser$result;
/*. . . . . . . . . . . . . . . . . . . .*/
case 6: // hdr ::= STRICTGRAPH optGraphName
{
Object RESULT = null;
int nameleft = ((java_cup.runtime.Symbol)CUP$Parser$stack.elementAt(CUP$Parser$top-0)).left;
int nameright = ((java_cup.runtime.Symbol)CUP$Parser$stack.elementAt(CUP$Parser$top-0)).right;
String name = (String)((java_cup.runtime.Symbol) CUP$Parser$stack.elementAt(CUP$Parser$top-0)).value;
startGraph(name,true,false);
CUP$Parser$result = new java_cup.runtime.Symbol(10/*hdr*/, ((java_cup.runtime.Symbol)CUP$Parser$stack.elementAt(CUP$Parser$top-1)).left, ((java_cup.runtime.Symbol)CUP$Parser$stack.elementAt(CUP$Parser$top-0)).right, RESULT);
}
return CUP$Parser$result;
/*. . . . . . . . . . . . . . . . . . . .*/
case 5: // hdr ::= optStrict graphType optGraphName
{
Object RESULT = null;
int strictleft = ((java_cup.runtime.Symbol)CUP$Parser$stack.elementAt(CUP$Parser$top-2)).left;
int strictright = ((java_cup.runtime.Symbol)CUP$Parser$stack.elementAt(CUP$Parser$top-2)).right;
Boolean strict = (Boolean)((java_cup.runtime.Symbol) CUP$Parser$stack.elementAt(CUP$Parser$top-2)).value;
int typeleft = ((java_cup.runtime.Symbol)CUP$Parser$stack.elementAt(CUP$Parser$top-1)).left;
int typeright = ((java_cup.runtime.Symbol)CUP$Parser$stack.elementAt(CUP$Parser$top-1)).right;
Boolean type = (Boolean)((java_cup.runtime.Symbol) CUP$Parser$stack.elementAt(CUP$Parser$top-1)).value;
int nameleft = ((java_cup.runtime.Symbol)CUP$Parser$stack.elementAt(CUP$Parser$top-0)).left;
int nameright = ((java_cup.runtime.Symbol)CUP$Parser$stack.elementAt(CUP$Parser$top-0)).right;
String name = (String)((java_cup.runtime.Symbol) CUP$Parser$stack.elementAt(CUP$Parser$top-0)).value;
startGraph(name,type.booleanValue(),strict.booleanValue());
CUP$Parser$result = new java_cup.runtime.Symbol(10/*hdr*/, ((java_cup.runtime.Symbol)CUP$Parser$stack.elementAt(CUP$Parser$top-2)).left, ((java_cup.runtime.Symbol)CUP$Parser$stack.elementAt(CUP$Parser$top-0)).right, RESULT);
}
return CUP$Parser$result;
/*. . . . . . . . . . . . . . . . . . . .*/
case 4: // graph ::=
{
Object RESULT = null;
graph = new Graph("empty");
//((Parser)(CUP$parser)).report_warning ("The graph to parse is empty.", null);
((Parser)(parser)).report_warning ("The graph to parse is empty.", null);
CUP$Parser$result = new java_cup.runtime.Symbol(9/*graph*/, ((java_cup.runtime.Symbol)CUP$Parser$stack.elementAt(CUP$Parser$top-0)).right, ((java_cup.runtime.Symbol)CUP$Parser$stack.elementAt(CUP$Parser$top-0)).right, RESULT);
}
return CUP$Parser$result;
/*. . . . . . . . . . . . . . . . . . . .*/
case 3: // graph ::= error
{
Object RESULT = null;
int valleft = ((java_cup.runtime.Symbol)CUP$Parser$stack.elementAt(CUP$Parser$top-0)).left;
int valright = ((java_cup.runtime.Symbol)CUP$Parser$stack.elementAt(CUP$Parser$top-0)).right;
Object val = (Object)((java_cup.runtime.Symbol) CUP$Parser$stack.elementAt(CUP$Parser$top-0)).value;
//CUP$parser.report_error ("An error was encountered while graph parsing (" + val.toString() + ").", null);
parser.report_error ("An error was encountered while graph parsing (" + val.toString() + ").", null);
CUP$Parser$result = new java_cup.runtime.Symbol(9/*graph*/, ((java_cup.runtime.Symbol)CUP$Parser$stack.elementAt(CUP$Parser$top-0)).left, ((java_cup.runtime.Symbol)CUP$Parser$stack.elementAt(CUP$Parser$top-0)).right, RESULT);
}
return CUP$Parser$result;
/*. . . . . . . . . . . . . . . . . . . .*/
case 2: // graph ::= hdr NT$0 body
{
Object RESULT = null;
// propagate RESULT from NT$0
if ( ((java_cup.runtime.Symbol) CUP$Parser$stack.elementAt(CUP$Parser$top-1)).value != null )
RESULT = (Object) ((java_cup.runtime.Symbol) CUP$Parser$stack.elementAt(CUP$Parser$top-1)).value;
closeGraph();
CUP$Parser$result = new java_cup.runtime.Symbol(9/*graph*/, ((java_cup.runtime.Symbol)CUP$Parser$stack.elementAt(CUP$Parser$top-2)).left, ((java_cup.runtime.Symbol)CUP$Parser$stack.elementAt(CUP$Parser$top-0)).right, RESULT);
}
return CUP$Parser$result;
/*. . . . . . . . . . . . . . . . . . . .*/
case 1: // NT$0 ::=
{
Object RESULT = null;
openGraph();
CUP$Parser$result = new java_cup.runtime.Symbol(32/*NT$0*/, ((java_cup.runtime.Symbol)CUP$Parser$stack.elementAt(CUP$Parser$top-0)).right, ((java_cup.runtime.Symbol)CUP$Parser$stack.elementAt(CUP$Parser$top-0)).right, RESULT);
}
return CUP$Parser$result;
/*. . . . . . . . . . . . . . . . . . . .*/
case 0: // $START ::= graph EOF
{
Object RESULT = null;
int start_valleft = ((java_cup.runtime.Symbol)CUP$Parser$stack.elementAt(CUP$Parser$top-1)).left;
int start_valright = ((java_cup.runtime.Symbol)CUP$Parser$stack.elementAt(CUP$Parser$top-1)).right;
Object start_val = (Object)((java_cup.runtime.Symbol) CUP$Parser$stack.elementAt(CUP$Parser$top-1)).value;
RESULT = start_val;
CUP$Parser$result = new java_cup.runtime.Symbol(0/*$START*/, ((java_cup.runtime.Symbol)CUP$Parser$stack.elementAt(CUP$Parser$top-1)).left, ((java_cup.runtime.Symbol)CUP$Parser$stack.elementAt(CUP$Parser$top-0)).right, RESULT);
}
/* ACCEPT */
CUP$Parser$parser.done_parsing();
return CUP$Parser$result;
/* . . . . . .*/
default:
throw new Exception(
"Invalid action number found in internal parse table");
}
}
}
att/grappa/Subgraph.java
att/grappa/Subgraph.java/*
* This software may only be used by you under license from AT&T Corp.
* ("AT&T"). A copy of AT&T's Source Code Agreement is available at
* AT&T's Internet website having the URL:
*
* If you received this software without first entering into a license
* with AT&T, you have an infringing copy of this software and cannot use
* it without violating AT&T’s intellectual property rights.
*/
package att.grappa;
import java.io.*;
import java.util.*;
/**
* This class describes a subgraph, which can consist of
* nodes, edges and other subgraphs. Note: The topmost
* or root subgraph is the entire graph (the Graph object), which is
* an extension of this class.
*
* @version 1.2, 26 May 2005; Copyright 1996 – 2005 by AT&T Corp.
* @author John Mocenigo, Research @ AT&T Labs
* @see Graph
*/
public class Subgraph extends Element
implements Comparator
{
/**
* Default graph name prefix used by setName().
*
* @see Subgraph#setName()
*/
public final static String defaultNamePrefix = “G”;
// node, edge and graph dictionaries for this subgraph
private Hashtable nodedict = null;
private Hashtable edgedict = null;
private Hashtable graphdict = null;
// indicators for dislaying element labels when drawing
private boolean nodeLabels = true;
private boolean edgeLabels = true;
private boolean subgLabels = true;
// default node attributes
private Hashtable nodeAttributes = null;
// default edge attributes
private Hashtable edgeAttributes = null;
// for cluster subgraphs
private boolean cluster = false;
/**
* Reference to the current selection (or vector of selections).
* Normally set and used by a GrappaAdapter.
*/
public Object currentSelection = null;
/**
* This constructor is needed by the Graph constructor
*/
Subgraph() {
//super();
cluster = true; // the root is a cluster subgraph
subgraphAttrsOfInterest();
}
/**
* Use this constructor when creating a subgraph within a subgraph.
*
* @param subg the parent subgraph.
* @param name the name of this subgraph.
*/
public Subgraph(Subgraph subg, String name) {
super(SUBGRAPH,subg);
setName(name);
Enumeration enm = subg.getNodeAttributePairs();
while(enm.hasMoreElements()) {
setNodeAttribute((Attribute)enm.nextElement());
}
enm = subg.getEdgeAttributePairs();
while(enm.hasMoreElements()) {
setEdgeAttribute((Attribute)enm.nextElement());
}
enm = subg.getLocalAttributePairs();
while(enm.hasMoreElements()) {
setAttribute((Attribute)enm.nextElement());
}
subgraphAttrsOfInterest();
}
/**
* Use this constructor when creating a subgraph within a subgraph
* with an automatically generated name.
*
* @param subg the parent subgraph.
* @see Subgraph#setName()
*/
public Subgraph(Subgraph subg) {
this(subg,(String)(null));
}
// a listing of the attributes of interest for Subgraphs
private void subgraphAttrsOfInterest() {
//attrOfInterest(BBOX_ATTR);
attrOfInterest(MINBOX_ATTR);
attrOfInterest(MINSIZE_ATTR);
attrOfInterest(LABEL_ATTR);
attrOfInterest(LP_ATTR);
attrOfInterest(STYLE_ATTR);
}
/**
* Check if this element is a subgraph.
* Useful for testing the subclass type of a Element object.
*
* @return true if this object is a Subgraph.
*/
public boolean isSubgraph() {
return(true);
}
/**
* Get the type of this element.
* Useful for distinguishing Element objects.
*
* @return the class variable constant SUBGRAPH.
* @see GrappaConstants#SUBGRAPH
*/
public int getType() {
return(SUBGRAPH);
}
/**
* Generates and sets the name for this subgraph.
* The generated name is the concatenation of the
* Subgraph.defaultNamePrefix with the numeric
* id of this subgraph Instance.
* Implements the abstract Element method.
*
* @see Element#getId()
*/
void setName() {
String oldName = name;
while(true) {
name = Subgraph.defaultNamePrefix + getId() + “_” + System.currentTimeMillis();
if(getGraph().findSubgraphByName(name) == null) {
break;
}
}
// update subgraph graph dictionary
if(getSubgraph() != null) {
if(oldName != null) {
getSubgraph().removeSubgraph(oldName);
}
getSubgraph().addSubgraph(this);
}
canonName = null;
}
/**
* Sets the subgraph name to a copy of the supplied argument.
* When the argument is null, setName() is called.
* When the name is not unique or when the name has the same format as
* that generated by setName(), a IllegalArgumentException is thrown.
*
* @param newName the new name for the subgraph.
* @see Subgraph#setName()
*/
public void setName(String newName) throws IllegalArgumentException {
if(newName == null) {
setName();
return;
}
String oldName = name;
// test if the new name is the same as the old name (if any)
if(oldName != null && oldName.equals(newName)) {
return;
}
// is name unique?
if(getGraph().findSubgraphByName(newName) != null) {
throw new IllegalArgumentException(“graph name (” + newName + “) is not unique”);
}
name = newName;
if(name.startsWith(“cluster”)) {
cluster = true;
}
// update subgraph graph dictionary
if(getSubgraph() != null) {
if(oldName != null) {
getSubgraph().removeSubgraph(oldName);
}
getSubgraph().addSubgraph(this);
}
canonName = null;
}
/**
* Check if the subgraph is a cluster subgraph.
*
* @return true, if the graph is a cluster subgraph.
*/
public boolean isCluster() {
return cluster;
}
/**
* Check if the subgraph is the root of the graph.
*
* @return true, if the graph is the root of the graph.
*/
public boolean isRoot() {
return (this == (Subgraph)getGraph());
}
/**
* Gets the subgraph-specific default attribute for the named node attribute.
*
* @param key the name of the node attribute pair to be retrieved.
* @return the requested attribute pair or null if not found.
*/
public Attribute getNodeAttribute(String key) {
if(nodeAttributes == null) return(null);
return((Attribute)(nodeAttributes.get(key)));
}
/**
* Gets the subgraph-specific default value for the named node attribute.
*
* @param key the name of the node attribute pair to be retrieved.
* @return the requested attribute value or null if not found.
*/
public Object getNodeAttributeValue(String key) {
Attribute attr;
if(nodeAttributes == null) return(null);
if((attr = (Attribute)(nodeAttributes.get(key))) == null) return(null);
return(attr.getValue());
}
/**
* Gets an enumeration of the subgraph-specific node attribute keys
*
* @return an enumeration of String objects.
*/
public Enumeration getNodeAttributeKeys() {
if(nodeAttributes == null) return Grappa.emptyEnumeration.elements();
return(nodeAttributes.keys());
}
/**
* Gets an enumeration of the subgraph-specific node attributes
*
* @return an enumeration of Attribute objects.
*/
public Enumeration getNodeAttributePairs() {
if(nodeAttributes == null) return Grappa.emptyEnumeration.elements();
return(nodeAttributes.elements());
}
/**
* Sets the subgraph-specific default for the specified node attribute.
* If the attribute is not from the parent subgraph, then
* setNodeAttribute(attr.getName(), attr.getValue()) is called.
*
* @param attr the node Attribute object to set as a default.
* @return the Attribute object previously stored for this attribute, if any.
* @see Subgraph#setNodeAttribute(java.lang.String, java.lang.String)
*/
public Object setNodeAttribute(Attribute attr) {
if(attr == null) return null;
if(nodeAttributes == null) {
nodeAttributes = new Hashtable();
}
// check to see if attr is being passed down the subgraph chain
Subgraph sg = getSubgraph();
Attribute prntAttr = (sg==null)?null:sg.getNodeAttribute(attr.getName());
if(attr != prntAttr) {
// it’s not, so use the other method;
// use getStringValue to make sure value is treated properly
// when converted to an Object
return setNodeAttribute(attr.getName(),attr.getStringValue());
}
Object oldValue = null;
Attribute newAttr = null;
Attribute crntAttr = getNodeAttribute(attr.getName());
if(attr == crntAttr) return attr.getValue();
if(crntAttr == null) {
if(attr.getValue() == null) {
return null;
}
nodeAttributes.put(attr.getName(),crntAttr = attr);
//System.err.println(“Adding passthru1 node attr(“+attr.getName()+”,”+attr.getValue()+”) to “+getName());
// it’s a pass down, so no need to set observers
} else {
oldValue = crntAttr.getValue();
crntAttr.setChanged(); // so notifyObservers is sure to be called
// it’s a pass down, so pass it down
nodeAttributes.put(attr.getName(),attr);
//System.err.println(“Adding passthru2 node attr(“+attr.getName()+”,”+attr.getValue()+”) to “+getName());
// this is why we need notifyObservers called
newAttr = attr;
}
// this should only be possible when “else” above has occurred
if(crntAttr.hasChanged()) {
crntAttr.notifyObservers(new Object[] { newAttr, new Long(System.currentTimeMillis()) });
}
return oldValue;
}
/**
* Sets the subgraph-specific default using the specified name/value
* pair. A new attribute will be created if needed.
*
* @param name the node attribute name
* @param value the node attribute value
* @return the Attribute object previously stored for this attribute, if any.
*/
public Object setNodeAttribute(String name, Object value) {
if(nodeAttributes == null) {
nodeAttributes = new Hashtable();
}
if(name == null) {
throw new IllegalArgumentException(“cannot set an attribute using a null name”);
}
// check to see if this name value is the same as the parent default
Subgraph sg = getSubgraph();
Attribute prntAttr = (sg==null)?null:sg.getNodeAttribute(name);
//if(prntAttr != null && value != null ) {
//System.err.println(“check new node attr (“+name+”,”+value+”) against (“+prntAttr.getName()+”,”+prntAttr.getValue()+”)”);
//if(name.equals(prntAttr.getName()) && value.equals(prntAttr.getValue())) {
// it is, so call other form
//System.err.println(“set node attr to same as default (“+name+”,”+value+”)”);
//return setNodeAttribute(prntAttr);
//}
//}
Object oldValue = null;
Attribute crntAttr = getNodeAttribute(name);
if(crntAttr == null || crntAttr == prntAttr) {
if(value == null) {
return null;
}
nodeAttributes.put(name,(crntAttr = new Attribute(NODE,name,value)));
// TODO: scan subnodes to see if this attr is of interest and then add it
// to observer list, but for now leave it
//
//System.err.println(“adding new node attr(“+name+”,”+value+”) to “+getName());
/*
* just concerned with subgraphs that share the same default (or null)
* and nodes that do not have a local attribute
*/
} else {
oldValue = crntAttr.getValue();
if(value == null) {
if(prntAttr == null) {
removeNodeAttribute(name);
return oldValue;
} else {
return setNodeAttribute(prntAttr);
}
} else {
crntAttr.setValue(value);
//System.err.println(“changing node attr(“+name+”,”+value+”) in “+getName());
}
}
if(crntAttr.hasChanged()) {
crntAttr.notifyObservers(new Long(System.currentTimeMillis()));
}
return oldValue;
}
/*
* Remove named default node attribute (assumes there is no default in
* the subgraph chain).
*
* @param name the name of the attribute to remove
*/
private void removeNodeAttribute(String name) {
if(name == null || nodeAttributes == null) return;
//System.err.println(“Remove ‘” + name + “‘ from ” + getName());
Attribute attr = (Attribute)nodeAttributes.remove(name);
if(attr == null) return;
attr.setValue(“”);
if(attr.hasChanged()) attr.notifyObservers(new Long(System.currentTimeMillis()));
attr.deleteObservers();
}
/**
* Sets the subgraph-specific default for the specified edge attribute.
* If the attribute is not from the parent subgraph, then
* setEdgeAttribute(attr.getName(), attr.getValue()) is called.
*
* @param attr the edge attribute pair to set.
* @return the attribute pair previously stored for this attribute.
* @see Subgraph#setEdgeAttribute(java.lang.String, java.lang.String)
*/
public Object setEdgeAttribute(Attribute attr) {
if(attr == null) return null;
if(edgeAttributes == null) {
edgeAttributes = new Hashtable();
}
// check to see if attr is being passed down the subgraph chain
Subgraph sg = getSubgraph();
Attribute prntAttr = (sg==null)?null:sg.getEdgeAttribute(attr.getName());
if(attr != prntAttr) {
// it’s not, so use the other method;
// use getStringValue to make sure value is treated properly
// when converted to an Object
return setEdgeAttribute(attr.getName(),attr.getStringValue());
}
Object oldValue = null;
Attribute newAttr = null;
Attribute crntAttr = getEdgeAttribute(attr.getName());
if(attr == crntAttr) return attr.getValue();
if(crntAttr == null) {
if(attr.getValue() == null) {
return null;
}
edgeAttributes.put(attr.getName(),crntAttr = attr);
//System.err.println(“Adding passthru1 edge attr(“+attr.getName()+”,”+attr.getValue()+”) to “+getName());
// it’s a pass down, so no need to set observers
} else {
oldValue = crntAttr.getValue();
crntAttr.setChanged(); // so notifyObservers is sure to be called
// it’s a pass down, so pass it down
edgeAttributes.put(attr.getName(),attr);
//System.err.println(“Adding passthru2 edge attr(“+attr.getName()+”,”+attr.getValue()+”) to “+getName());
newAttr = attr;
}
// this should only be possible when “else” above has occurred
if(crntAttr.hasChanged()) {
crntAttr.notifyObservers(new Object[] { newAttr, new Long(System.currentTimeMillis()) });
}
return oldValue;
}
/**
* Sets the subgraph-specific default using the specified name/value
* pair. A new attribute will be created if needed.
*
* @param name the edge attribute name
* @param value the edge attribute value
* @return the attribute pair previously stored for this attribute.
*/
public Object setEdgeAttribute(String name, Object value) {
if(edgeAttributes == null) {
edgeAttributes = new Hashtable();
}
if(name == null) {
throw new IllegalArgumentException(“cannot set an attribute using a null name”);
}
// check to see if this name value is the same as the parent default
Subgraph sg = getSubgraph();
Attribute prntAttr = (sg==null)?null:sg.getEdgeAttribute(name);
//if(prntAttr != null && value != null ) {
//if(name.equals(prntAttr.getName()) && value.equals(prntAttr.getValue())) {
// it is, so call other form
//return setEdgeAttribute(prntAttr);
//}
//}
Object oldValue = null;
Attribute crntAttr = getEdgeAttribute(name);
if(crntAttr == null || crntAttr == prntAttr) {
if(value == null) {
return null;
}
edgeAttributes.put(name,(crntAttr = new Attribute(EDGE,name,value)));
//System.err.println(“adding new edge attr(“+name+”,”+value+”) to “+getName());
/*
* just concerned with subgraphs that share the same default (or null)
* and edges that do not have a local attribute
*/
} else {
oldValue = crntAttr.getValue();
if(value == null) {
if(prntAttr == null) {
removeEdgeAttribute(name);
return oldValue;
} else {
return setEdgeAttribute(prntAttr);
}
} else {
crntAttr.setValue(value);
//System.err.println(“changing edge attr(“+name+”,”+value+”) in “+getName());
}
}
if(crntAttr.hasChanged()) {
crntAttr.notifyObservers(new Long(System.currentTimeMillis()));
}
return oldValue;
}
/*
* Remove named default edge attribute (assumes there is no default in
* the subgraph chain).
*
* @param name the name of the attribute to remove
*/
private void removeEdgeAttribute(String name) {
if(name == null || edgeAttributes == null) return;
Attribute attr = (Attribute)edgeAttributes.remove(name);
if(attr == null) return;
attr.setValue(“”);
if(attr.hasChanged()) attr.notifyObservers(new Long(System.currentTimeMillis()));
attr.deleteObservers();
}
/**
* Sets the subgraph-specific default for the specified graph attribute.
* If the attribute is not from the parent subgraph, then
* setAttribute(attr.getName(), attr.getValue()) is called.
* Overrides Element method.
*
* @param attr the graph attribute pair to set.
* @return the attribute pair previously stored for this attribute.
* @see Subgraph#setAttribute(java.lang.String, java.lang.String)
*/
public Object setAttribute(Attribute attr) {
if(attr == null) return null;
if(attributes == null) {
attributes = new Hashtable();
}
// check to see if attr is being passed down the subgraph chain
Subgraph sg = getSubgraph();
Attribute prntAttr = (sg==null)?null:sg.getLocalAttribute(attr.getName());
if(attr != prntAttr) {
// it’s not, so use the other method;
// use getStringValue to make sure value is treated properly
// when converted to an Object
return setAttribute(attr.getName(),attr.getStringValue());
}
Object oldValue = null;
Attribute newAttr = null;
Attribute crntAttr = getLocalAttribute(attr.getName());
if(attr == crntAttr) return attr.getValue();
if(crntAttr == null) {
if(attr.getValue() == null) {
return null;
}
attributes.put(attr.getName(),crntAttr = attr);
//System.err.println(“Adding passthru1 graph attr(“+attr.getName()+”,”+attr.getValue()+”) to “+getName());
// it’s a pass down, so no need to set observers
} else {
oldValue = crntAttr.getValue();
crntAttr.setChanged(); // so notifyObservers is sure to be called
// it’s a pass down, so pass it down
attributes.put(attr.getName(),attr);
//System.err.println(“Adding passthru2 graph attr(“+attr.getName()+”,”+attr.getValue()+”) to “+getName());
// this is why we need notifyObservers called
newAttr = attr;
}
// this should only be possible when “else” above has occurred
if(crntAttr.hasChanged()) {
crntAttr.notifyObservers(new Object[] { newAttr, new Long(System.currentTimeMillis()) });
}
return oldValue;
}
/**
* Sets the subgraph-specific default using the specified name/value
* pair. A new attribute will be created if needed.
* Overrides Element method.
*
* @param name the graph attribute name
* @param value the graph attribute value
* @return the attribute pair previously stored for this attribute.
*/
public Object setAttribute(String name, Object value) {
if(attributes == null) {
attributes = new Hashtable();
}
if(name == null) {
throw new IllegalArgumentException(“cannot set an attribute using a null name”);
}
// check to see if this name value is the same as the parent default
Subgraph sg = getSubgraph();
Attribute prntAttr = (sg==null)?null:sg.getLocalAttribute(name);
//if(prntAttr != null && value != null ) {
//if(name.equals(prntAttr.getName()) && value.equals(prntAttr.getValue())) {
// it is, so call other form
//return setAttribute(prntAttr);
//}
//}
Object oldValue = null;
Attribute crntAttr = getLocalAttribute(name);
if(crntAttr == null || crntAttr == prntAttr) {
if(value == null) {
return null;
} else if(value instanceof String && ((String)value).trim().length() == 0 && Attribute.attributeType(getType(),name) != STRING_TYPE) {
return null;
}
attributes.put(name,(crntAttr = new Attribute(SUBGRAPH,name,value)));
if(grappaNexus != null && isOfInterest(name)) {
crntAttr.addObserver(grappaNexus);
}
//System.err.println(“adding new graph attr(“+name+”,”+value+”) to “+getName());
} else {
oldValue = crntAttr.getValue();
if(value == null) {
if(prntAttr == null) {
//System.err.println(“removing graph attr(“+name+”,”+value+”) in “+getName());
super.setAttribute(name,null);
return oldValue;
} else {
//System.err.println(“defaulting graph attr(“+name+”,”+value+”) in “+getName());
return setAttribute(prntAttr);
}
} else if(value instanceof String && ((String)value).trim().length() == 0 && Attribute.attributeType(getType(),name) != STRING_TYPE) {
if(prntAttr == null) {
//System.err.println(“removing graph attr(“+name+”,”+value+”) in “+getName());
super.setAttribute(name,null);
return oldValue;
} else {
//System.err.println(“defaulting graph attr(“+name+”,”+value+”) in “+getName());
return setAttribute(prntAttr);
}
} else {
crntAttr.setValue(value);
//System.err.println(“changing graph attr(“+name+”,”+value+”) in “+getName());
}
}
if(crntAttr.hasChanged()) {
crntAttr.notifyObservers(new Long(System.currentTimeMillis()));
}
return oldValue;
}
/**
* Gets the subgraph-specific default attribute for the named edge attribute.
*
* @param key the name of the edge attribute pair to be retrieved.
* @return the requested attribute pair or null if not found.
*/
public Attribute getEdgeAttribute(String key) {
if(edgeAttributes == null) return(null);
return((Attribute)(edgeAttributes.get(key)));
}
/**
* Gets the subgraph-specific default value for the named edge attribute.
*
* @param key the name of the edge attribute pair to be retrieved.
* @return the requested attribute value or null if not found.
*/
public Object getEdgeAttributeValue(String key) {
Attribute attr;
if(edgeAttributes == null) return(null);
if((attr = (Attribute)(edgeAttributes.get(key))) == null) return(null);
return(attr.getValue());
}
/**
* Gets an enumeration of the subgraph-specific edge attribute keys
*
* @return an enumeration of String objects.
*/
public Enumeration getEdgeAttributeKeys() {
if(edgeAttributes == null) return Grappa.emptyEnumeration.elements();
return(edgeAttributes.keys());
}
/**
* Gets an enumeration of the subgraph-specific edge attributes
*
* @return an enumeration of Attribute objects.
*/
public Enumeration getEdgeAttributePairs() {
if(edgeAttributes == null) return Grappa.emptyEnumeration.elements();
return(edgeAttributes.elements());
}
/**
* Get the bounding box of the subgraph.
*
* @return the bounding box of the subgraph.
*/
public java.awt.geom.Rectangle2D getBoundingBox() {
java.awt.geom.Rectangle2D bbox = null;
if(grappaNexus == null || (bbox = grappaNexus.bbox) == null) {
if(grappaNexus == null) {
buildShape();
}
bbox = null;
Element elem = null;
GraphEnumeration enm = elements();
while(enm.hasMoreElements()) {
elem = enm.nextGraphElement();
if(elem == (Element)this) continue;
switch(elem.getType()) {
case NODE:
case EDGE:
elem.buildShape();
if(bbox == null) {
bbox = elem.grappaNexus.getBounds2D();
} else {
bbox.add(elem.grappaNexus.getBounds2D());
}
break;
case SUBGRAPH:
if(bbox == null) {
bbox = ((Subgraph)elem).getBoundingBox();
} else {
bbox.add(((Subgraph)elem).getBoundingBox());
}
break;
default: // cannot happen
throw new InternalError(“unknown type (” + elem.getType() + “)”);
}
}
GrappaSize minSize = (GrappaSize)getAttributeValue(MINSIZE_ATTR);
if(minSize != null) {
if(bbox == null) {
bbox = new java.awt.geom.Rectangle2D.Double(0,0,minSize.getWidth(),minSize.getHeight());
} else {
bbox.add(new java.awt.geom.Rectangle2D.Double(bbox.getCenterX()-(minSize.getWidth()/2.0),bbox.getCenterY()-(minSize.getHeight()/2.0),minSize.getWidth(),minSize.getHeight()));
}
}
GrappaBox minBox = (GrappaBox)getThisAttributeValue(MINBOX_ATTR);
if(minBox != null) {
if(bbox == null) {
bbox = new java.awt.geom.Rectangle2D.Double(minBox.x,minBox.y,minBox.width,minBox.height);
} else {
bbox.add(new java.awt.geom.Rectangle2D.Double(minBox.x,minBox.y,minBox.width,minBox.height));
}
}
minBox = (GrappaBox)getThisAttributeValue(BBOX_ATTR);
if(minBox != null) {
if(bbox == null) {
bbox = new java.awt.geom.Rectangle2D.Double(minBox.x,minBox.y,minBox.width,minBox.height);
} else {
bbox.add(new java.awt.geom.Rectangle2D.Double(minBox.x,minBox.y,minBox.width,minBox.height));
}
}
if(bbox == null) {
bbox = new java.awt.geom.Rectangle2D.Double();
}
bbox.add(bbox.getX()+bbox.getWidth()+1,bbox.getY()+bbox.getHeight()+1);
grappaNexus.bbox = bbox;
if(Grappa.provideBBoxAttribute) {
setAttribute(BBOX_ATTR, new GrappaBox(bbox));
}
grappaNexus.updateShape();
}
return((java.awt.geom.Rectangle2D)(bbox.clone()));
}
/**
* Removes bounding box information from this subgraph and any
* contained subgraphs including the BBOX_ATTR value and then
* recomputes the bounding boxes.
*
* @return the new bounding box of the subgraph.
*/
public java.awt.geom.Rectangle2D resetBoundingBox() {
Element elem = null;
GraphEnumeration enm = elements(SUBGRAPH);
while(enm.hasMoreElements()) {
elem = enm.nextGraphElement();
elem.grappaNexus.bbox = null;
elem.setAttribute(BBOX_ATTR, null);
}
return(getBoundingBox());
}
/**
* Prints an ascii description of each graph element to the supplied stream.
*
* @param output the OutputStream for writing the graph description.
*/
public void printSubgraph(PrintWriter out) {
Graph graph = getGraph();
String indent = new String(graph.getIndent());
if(Grappa.printVisibleOnly && (!visible || grappaNexus.style.invis))
return;
if(getSubgraph() == null) {
// this subgraph is the root
out.println(indent + (graph.isStrict()?”strict “:””) + (graph.isDirected()?”digraph”:”graph”) + ” ” + graph.toString() + ” {“);
} else if(getName().startsWith(ANONYMOUS_PREFIX)) {
out.println(indent + “{“);
} else {
out.println(indent + “subgraph ” + this.toString() + ” {“);
}
graph.incrementIndent();
printDflt(out,SUBGRAPH);
printDflt(out,NODE);
printDflt(out,EDGE);
if(graphdict != null && !graphdict.isEmpty()) {
Enumeration elems = graphdict.elements();
while(elems.hasMoreElements()) {
((Subgraph)(elems.nextElement())).printSubgraph(out);
}
}
if(nodedict != null && !nodedict.isEmpty()) {
Enumeration elems = nodedict.elements();
while(elems.hasMoreElements()) {
((Node)(elems.nextElement())).printNode(out);
}
}
if(edgedict != null && !edgedict.isEmpty()) {
Enumeration elems = edgedict.elements();
while(elems.hasMoreElements()) {
((Edge)(elems.nextElement())).printEdge(out);
}
}
graph.decrementIndent();
out.println(indent + “}”);
}
// print the subgraph default elements
private void printDflt(PrintWriter out, int type) {
String indent = new String(getGraph().getIndent());
Hashtable attr = null;
String label = null;
switch(type) {
case SUBGRAPH:
attr = attributes;
label = “graph”;
break;
case NODE:
attr = nodeAttributes;
label = “node”;
break;
case EDGE:
attr = edgeAttributes;
label = “edge”;
break;
}
if(attr == null || attr.isEmpty()) {
getGraph().printError(“no ” + label + ” atrtibutes for ” + getName());
return;
}
getGraph().incrementIndent();
printDfltAttr(out,attr,type,indent + label + ” [“, indent + “];”);
getGraph().decrementIndent();
}
// print the subgraph default element attribute values
private void printDfltAttr(PrintWriter out, Hashtable dfltAttr, int type, String prefix, String suffix) {
String indent = new String(getGraph().getIndent());
String value;
String key;
Attribute attr;
int nbr = 0;
Enumeration attrs = dfltAttr.elements();
Subgraph sg = getSubgraph();
Hashtable printlist = null;
if(type == SUBGRAPH && (Grappa.usePrintList || usePrintList)) {
printlist = (Hashtable)getAttributeValue(PRINTLIST_ATTR);
}
while(attrs.hasMoreElements()) {
attr = (Attribute)(attrs.nextElement());
if(attr == null) continue;
key = attr.getName();
if(printlist != null && printlist.get(key) == null) continue;
value = attr.getStringValue();
if(Grappa.elementPrintAllAttributes || Grappa.elementPrintDefaultAttributes || printAllAttributes || printDefaultAttributes || !attr.equalsValue(getParentDefault(type,key))) {
nbr++;
if(nbr == 1) {
out.println(prefix);
out.print(indent + key + ” = ” + canonString(value));
} else {
out.println(“,”);
out.print(indent + key + ” = ” + canonString(value));
}
}
}
if(nbr > 0) {
out.println();
out.println(suffix);
out.println();
}
}
/**
* Returns the attribute conversion type for the supplied attribute name.
* After subgraph specific attribute name/type mappings are checked,
* mappings at the element level are checked.
*
* @param attrname the attribute name
* @return the currently associated attribute type
*/
public static int attributeType(String attrname) {
int convtype = -1;
int hashCode;
if(attrname != null) {
hashCode = attrname.hashCode();
if(hashCode == MARGIN_HASH && attrname.equals(MARGIN_ATTR)) {
convtype = SIZE_TYPE;
} else if(hashCode == MCLIMIT_HASH && attrname.equals(MCLIMIT_ATTR)) {
convtype = DOUBLE_TYPE;
} else if(hashCode == MINBOX_HASH && attrname.equals(MINBOX_ATTR)) {
convtype = BOX_TYPE;
} else if(hashCode == NODESEP_HASH && attrname.equals(NODESEP_ATTR)) {
convtype = DOUBLE_TYPE;
} else if(hashCode == MINSIZE_HASH && attrname.equals(MINSIZE_ATTR)) {
convtype = SIZE_TYPE;
} else if(hashCode == NODESEP_HASH && attrname.equals(NODESEP_ATTR)) {
convtype = DOUBLE_TYPE;
} else if(hashCode == RANKSEP_HASH && attrname.equals(RANKSEP_ATTR)) {
convtype = DOUBLE_TYPE;
} else if(hashCode == SIZE_HASH && attrname.equals(SIZE_ATTR)) {
convtype = SIZE_TYPE;
} else {
return(Element.attributeType(attrname));
}
}
return(convtype);
}
// get the parent default attribute value for the specified type and key
private Attribute getParentDefault(int type, String key) {
Attribute attr = null;
Subgraph subg = getSubgraph();
switch(type) {
case SUBGRAPH:
while(subg != null && (attr = subg.getLocalAttribute(key)) == null) {
subg = subg.getSubgraph();
}
if(attr == null) {
attr = getGraph().getGlobalAttribute(SUBGRAPH,key);
}
return attr;
case NODE:
while(subg != null && (attr = subg.getNodeAttribute(key)) == null) {
subg = subg.getSubgraph();
}
if(attr == null) {
attr = getGraph().getGlobalAttribute(NODE,key);
}
return attr;
case EDGE:
while(subg != null && (attr = subg.getEdgeAttribute(key)) == null) {
subg = subg.getSubgraph();
}
if(attr == null) {
attr = getGraph().getGlobalAttribute(EDGE,key);
}
return attr;
}
return null;
}
/*
* Find an Element by name.
*
* @param type the type of the element
* @param name the name of the element
* @return the found element or null
*
* @see Subgraph#findNodeByName(java.lang.String)
* @see Subgraph#findEdgeByName(java.lang.String)
* @see Subgraph#findSubgraphByName(java.lang.String)
*/
private Element findElementByName(int type, String name) {
if(name == null) {
return(null);
}
return findElementInSubgraphByName(type,name);
}
// used above
private Element findElementInSubgraphByName(int type, String name) {
Element elem = null;
switch(type) {
case NODE:
if(nodedict != null) elem = (Element)nodedict.get(name);
break;
case EDGE:
if(edgedict != null) elem = (Element)edgedict.get(name);
break;
case SUBGRAPH:
if(graphdict != null) elem = (Element)graphdict.get(name);
break;
}
if(elem != null || graphdict == null) return elem;
Enumeration enm = graphdict.elements();
while(enm.hasMoreElements()) {
if((elem = ((Subgraph)enm.nextElement()).findElementInSubgraphByName(type,name)) != null) {
return elem;
}
}
return elem;
}
/**
* Searches current subgraph and, by recursion, descendent subgraphs
* for the node matching the supplied name.
*
* @param nodeName the name of the node to be found.
* @return the Node matching the name or null, if there is no match.
*/
public Node findNodeByName(String nodeName) {
return (Node)findElementByName(NODE,nodeName);
}
/**
* Searches current subgraph and, by recursion, descendent subgraphs
* for the edge matching the supplied name.
*
* @param edgeName the name of the edge to be found.
* @return the Edge matching the name or null, if there is no match.
*/
public Edge findEdgeByName(String edgeName) {
return (Edge)findElementByName(EDGE,edgeName);
}
/**
* Searches current subgraph and, by recursion, descendent subgraphs
* for the subgraph matching the supplied name.
*
* @param graphName the name of the subgraph to be found.
* @return the Subgraph matching the name or null, if there is no match.
*/
public Subgraph findSubgraphByName(String graphName) {
return (Subgraph)findElementByName(SUBGRAPH,graphName);
}
/**
* Creates a new element and adds it to the subgraph’s element dictionary.
* For nodes, the info vector can be null or contains:
*
-
*
- String – name of the node (optional, for automatic name generation)
*
* For edges, the info vector must contain (in this order) at least:
*
-
*
- Node – head node,
* - String – headport tag (or null),
* - Node – tail node,
*
* Optionally, the info vector can also contain at its end (in this order):
*
-
*
- String – tailport tag (or null),
* - String – a key for distinguishing multiple edges between the same nodes (or null),
*
* For subgraphs, the info vector can be null or contains:
*
-
*
- String – name of the subgraph (optional, for automatic name generation)
*
*
* @param type type of the element to be added
* @param info a vector specifics for the particular type of element being created
* @param attrs attributes describing the element to be created
* @exception InstantiationException whenever element cannot be created
*/
public Element createElement(int type, Object[] info, Attribute[] attrs) {
Element elem = null;
switch(type) {
case NODE:
String nodeName = null;
if(info != null && info.length >= 1) {
nodeName = (String)info[0];
}
Node node = new Node(this,nodeName);
if(attrs != null) {
for(int i = 0; i < attrs.length; i++) {
node.setAttribute(attrs[i]);
}
}
elem = (Element)node;
break;
case EDGE:
if(info == null || info.length < 3) {
throw new IllegalArgumentException("insufficient info supplied for edge creation");
}
Node head = (Node)info[0];
String headPort = (String)info[1];
Node tail = (Node)info[2];
String tailPort = null;
String key = null;
if(info.length > 3) {
tailPort = (String)info[3];
if(info.length > 4) {
key = (String)info[4];
}
}
Edge edge = new Edge(this,tail,tailPort,head,headPort,key);
if(attrs != null) {
for(int i = 0; i < attrs.length; i++) {
edge.setAttribute(attrs[i]);
}
}
elem = (Element)edge;
break;
case SUBGRAPH:
String subgName = null;
if(info != null && info.length >= 1) {
subgName = (String)info[0];
}
Subgraph newSubg = new Subgraph(this,subgName);
if(attrs != null) {
for(int i = 0; i < attrs.length; i++) {
newSubg.setAttribute(attrs[i]);
}
}
elem = (Subgraph)newSubg;
break;
default:
return null;
}
return elem;
}
/**
* Adds the specified node to the subgraph's Node dictionary.
*
* @param newNode the node to be added to the dictionary.
*/
public void addNode(Node newNode) {
if(newNode == null) return;
if(nodedict == null) {
nodedict = new Hashtable();
}
nodedict.put(newNode.getName(),newNode);
}
/**
* Removes the node matching the specified name from the subgraph's Node dictionary.
*
* @param nodeName the name of the node to be removed from the dictionary.
* @return the node that was removed.
*/
public Node removeNode(String nodeName) {
if(nodedict == null) return(null);
return((Node)(nodedict.remove(nodeName)));
}
/**
* Adds the specified edge to the subgraph's Edge dictionary.
*
* @param newEdge the edge to be added to the dictionary.
*/
public void addEdge(Edge newEdge) {
if(newEdge == null) return;
if(edgedict == null) {
edgedict = new Hashtable();
}
edgedict.put(newEdge.getName(),newEdge);
}
/**
* Removes the edge matching the specified name from the subgraph's Edge dictionary.
*
* @param edgeName the name of the edge to be removed from the dictionary.
* @return the edge that was removed.
*/
public Edge removeEdge(String edgeName) {
if(edgedict == null) return(null);
return((Edge)(edgedict.remove(edgeName)));
}
/**
* Adds the specified subgraph to the subgraph's graph dictionary.
*
* @param newGraph the subgraph to be added to the dictionary.
*/
public void addSubgraph(Subgraph newGraph) {
if(newGraph == null) return;
if(graphdict == null) {
graphdict = new Hashtable();
}
graphdict.put(newGraph.getName(),newGraph);
}
/**
* Removes the subgraph matching the specified name from the
* subgraph's graph dictionary.
*
* @param graphName the name of the subgraph to be removed from the dictionary.
* @return the subgraph that was removed.
*/
public Subgraph removeSubgraph(String graphName) {
if(graphdict == null) return(null);
return((Subgraph)(graphdict.remove(graphName)));
}
/**
* Set flag to indicate if subgraph labels should be rendered
*
* @return the previous value
*/
public boolean setShowSubgraphLabels(boolean value) {
boolean oldValue = subgLabels;
subgLabels = value;
return(oldValue);
}
/**
* Set flag to indicate if node labels should be rendered
*
* @return the previous value
*/
public boolean setShowNodeLabels(boolean value) {
boolean oldValue = nodeLabels;
nodeLabels = value;
return(oldValue);
}
/**
* Set flag to indicate if edge labels should be rendered
*
* @return the previous value
*/
public boolean setShowEdgeLabels(boolean value) {
boolean oldValue = edgeLabels;
edgeLabels = value;
return(oldValue);
}
/**
* Get flag that indicates if subgraph labels should be rendered
*
* @return the flag value
*/
public boolean getShowSubgraphLabels() {
return(subgLabels);
}
/**
* Get flag that indicates if node labels should be rendered
*
* @return the flag value
*/
public boolean getShowNodeLabels() {
return(nodeLabels);
}
/**
* Get flag that indicates if edge labels should be rendered
*
* @return the flag value
*/
public boolean getShowEdgeLabels() {
return(edgeLabels);
}
/**
* Check if the orientation of this subgraph is LR (left-to-right) as opposed
* to TB (top-to-bottom).
*
* @return true if the orientation is left-to-right.
*/
public boolean isLR() {
Attribute attr = getAttribute("rankdir");
if(attr == null) return false; // the default
String value = attr.getStringValue();
if(value == null) return false; // the default
if(value.equals("LR")) return true;
return false;
}
/**
* Adds a default tag for the specified element type within this subgraph.
*
* @param type the element type for this tag operation
* @param tag the tag to associate with this element type.
*/
public void addTypeTag(int type, String tag) {
if(tag == null || tag.indexOf(',') >= 0) {
throw new RuntimeException(“tag value null or contains a comma (” + tag + “)”);
}
Attribute attr = null;
Hashtable tags;
switch(type) {
case NODE:
attr = getNodeAttribute(TAG_ATTR);
break;
case EDGE:
attr = getEdgeAttribute(TAG_ATTR);
break;
case SUBGRAPH:
attr = getLocalAttribute(TAG_ATTR);
break;
}
if(attr == null) {
attr = new Attribute(type,TAG_ATTR,new Hashtable());
setAttribute(attr);
switch(type) {
case NODE:
setNodeAttribute(attr);
break;
case EDGE:
setEdgeAttribute(attr);
break;
case SUBGRAPH:
setAttribute(attr);
break;
}
}
tags = (Hashtable)(attr.getValue());
tags.put(tag,tag);
// if it becomes desireable to retain the original order, we
// could always use the value in the following (instead of
// what is done above) to reconstruct the original order
// (Note that no code makes use of the value at this point,
// so that would all have to be added in printAttributes, for
// example)
// tags.put(tag,new Long(System.currentTimeMillis()));
}
/**
* Check if the specified element type has the supplied default tag within
* this subgraph.
*
* @param type the element type for this tag operation
* @param tag tag value to be searched for
* @return true, if this subgraph contains the supplied tag as a default for the given type
*/
public boolean hasTypeTag(int type, String tag) {
Attribute attr = null;
Hashtable tags;
switch(type) {
case NODE:
attr = getNodeAttribute(TAG_ATTR);
break;
case EDGE:
attr = getEdgeAttribute(TAG_ATTR);
break;
case SUBGRAPH:
attr = getLocalAttribute(TAG_ATTR);
break;
}
if(attr == null) return false;
tags = (Hashtable)(attr.getValue());
if(tags == null || tags.size() == 0) return false;
return(tags.containsKey(tag));
}
/**
* Check if this element type has any default tags at all.
*
* @param type the element type for this tag operation
* @return true, if this Element has any tags
*/
public boolean hasTypeTags(int type) {
Attribute attr = null;
Hashtable tags;
switch(type) {
case NODE:
attr = getNodeAttribute(TAG_ATTR);
break;
case EDGE:
attr = getEdgeAttribute(TAG_ATTR);
break;
case SUBGRAPH:
attr = getLocalAttribute(TAG_ATTR);
break;
}
if(attr == null) return false;
tags = (Hashtable)(attr.getValue());
if(tags == null || tags.size() == 0) return false;
return(true);
}
/**
* Removes any and all default tags associated with this element type.
* @param type the element type for this tag operation
*/
public void removeTypeTags(int type) {
Attribute attr = null;
Hashtable tags;
switch(type) {
case NODE:
attr = getNodeAttribute(TAG_ATTR);
break;
case EDGE:
attr = getEdgeAttribute(TAG_ATTR);
break;
case SUBGRAPH:
attr = getLocalAttribute(TAG_ATTR);
break;
}
if(attr == null) return;
tags = (Hashtable)(attr.getValue());
if(tags == null || tags.size() == 0) return;
tags.clear();
}
/**
* Removes the specified tag from this element.
*
* @param type the element type for this tag operation
* @param tag the tag value to remove
*/
public void removeTypeTag(int type, String tag) {
Attribute attr = null;
Hashtable tags;
switch(type) {
case NODE:
attr = getNodeAttribute(TAG_ATTR);
break;
case EDGE:
attr = getEdgeAttribute(TAG_ATTR);
break;
case SUBGRAPH:
attr = getLocalAttribute(TAG_ATTR);
break;
}
if(attr == null) return;
tags = (Hashtable)(attr.getValue());
if(tags == null || tags.size() == 0) return;
tags.remove(tag);
}
/**
* Get a count of elements in this subgraph. No recursion to descendants
* is done.
*
* @param types a bitwise-oring of NODE, EDGE, SUBGRAPH to
* determine which element types should be in the count
* @return a count of the specified elements in this subgraph.
* @see GrappaConstants#NODE
* @see GrappaConstants#EDGE
* @see GrappaConstants#SUBGRAPH
*/
public int countOfLocalElements(int types) {
int count = 0;
if((types&NODE) != 0 && nodedict != null) count += nodedict.size();
if((types&EDGE) != 0 && edgedict != null) count += edgedict.size();
if((types&SUBGRAPH) != 0 && graphdict != null) count += graphdict.size();
return count;
}
/**
* Get a count of elements in this subgraph and, by recursion, descendant
* subgraphs. The subgraph itself is not counted.
*
* @param types a bitwise-oring of NODE, EDGE, SUBGRAPH to
* determine which element types should be in the count
* @return a count of the specified elements in this subgraph and its descendants.
* @see GrappaConstants#NODE
* @see GrappaConstants#EDGE
* @see GrappaConstants#SUBGRAPH
*/
public int countOfElements(int types) {
int count = 0;
if((types&NODE) != 0 && nodedict != null) count += nodedict.size();
if((types&EDGE) != 0 && edgedict != null) count += edgedict.size();
if(graphdict != null) {
if((types&SUBGRAPH) != 0) count += graphdict.size();
Enumeration enm = graphdict.elements();
while(enm.hasMoreElements()) {
count += ((Subgraph)enm.nextElement()).countOfElements(types);
}
}
return count;
}
/**
* Delete this subgraph or any contained subgraph, at any depth, if the
* subgraph contains no elements.
*/
public void removeEmptySubgraphs() {
if(
(graphdict == null || graphdict.size() == 0)
&&
(nodedict == null || nodedict.size() == 0)
&&
(edgedict == null || edgedict.size() == 0)
) {
delete();
return;
}
if(graphdict != null) {
Enumeration enm = graphdict.elements();
while(enm.hasMoreElements()) {
((Subgraph)enm.nextElement()).removeEmptySubgraphs();
}
}
}
/**
* @return true if this subgraph or any subgraph contained within
* this subgraph, at any depth, is empty.
*/
public boolean hasEmptySubgraphs() {
if(
(graphdict == null || graphdict.size() == 0)
&&
(nodedict == null || nodedict.size() == 0)
&&
(edgedict == null || edgedict.size() == 0)
) {
return(true);
}
if(graphdict != null) {
Enumeration enm = graphdict.elements();
while(enm.hasMoreElements()) {
if(((Subgraph)enm.nextElement()).hasEmptySubgraphs()) {
return(true);
}
}
}
return(false);
}
//
// Start PatchWork (similar to TreeMap) stuff
//
private double PATCHEDGE = 2;
private double PATCHEDGE2 = 2.0 * PATCHEDGE;
private Element[] sgPatches = null;
private Element[] elPatches = null;
private GrappaBox patch = null;
public void clearPatchWork() {
prepPatchWork(null, -1);
}
public void patchWork(java.awt.geom.Rectangle2D.Double r, boolean square, int mode) {
preparePatchWork(mode);
computePatchWork(r instanceof GrappaBox ? r : new GrappaBox(r), square);
if(mode == 0) {
Subgraph sg;
String style;
Attribute attr;
Enumeration enm = elements(Grappa.SUBGRAPH);
while(enm.hasMoreElements()) {
sg = (Subgraph)(enm.nextElement());
if(sg != this) {
attr = sg.getAttribute(STYLE_ATTR);
if(attr != null) {
style = attr.getStringValue();
sg.setAttribute(STYLE_ATTR,style != null && style.length() > 0 ? style + “,filled(false)” : null);
}
}
}
} else {
float sgtot = countOfElements(Grappa.SUBGRAPH) – 2;
float nbr = 0;
Subgraph sg;
String style;
Attribute attr;
Enumeration enm = elements(Grappa.SUBGRAPH);
while(enm.hasMoreElements()) {
sg = (Subgraph)(enm.nextElement());
if(sg != this) {
sg.setAttribute(COLOR_ATTR,java.awt.Color.getHSBColor((float)(0.05+0.9*(nbr++/sgtot)),(float)1.0,(float)1.0));
attr = sg.getAttribute(STYLE_ATTR);
if(attr == null) {
sg.setAttribute(STYLE_ATTR, “filled”);
} else {
style = attr.getStringValue();
sg.setAttribute(STYLE_ATTR,style == null || style.length() == 0 ? “filled” : style + “,filled”);
}
}
}
}
}
public double preparePatchWork(int mode) {
double total;
total = prepPatchWork(PATCH_ATTR, mode);
if(mode == 0) {
combPatchWork();
if(elPatches != null)
Arrays.sort(elPatches,0,elPatches.length,this);
}
return(total);
}
Element[] getPatches() {
return(elPatches);
}
private void combPatchWork() {
Hashtable dict;
Subgraph sg;
Element[] patches;
Element[] elpat;
Element[] sgpat;
Element[] tmparr;
patches = elPatches;
sgpat = sgPatches; // snapshot
if(sgpat != null && sgpat.length > 0) {
for(int i = 0; i < sgpat.length; i++) {
sg = (Subgraph)sgpat[i];
sg.combPatchWork();
elpat = sg.getPatches();
if(elpat != null && elpat.length > 0) {
if(patches == null || patches.length == 0)
patches = elpat;
else {
tmparr = new Element[patches.length + elpat.length];
System.arraycopy(patches,0,tmparr,0,patches.length);
System.arraycopy(elpat,0,tmparr,patches.length,elpat.length);
patches = tmparr;
}
}
}
}
sgPatches = null;
elPatches = patches;
}
private double prepPatchWork(String attrname, int mode) {
double total;
Enumeration enm;
Hashtable dict;
Object obj;
int m;
int n;
Subgraph sg;
Element el;
Element[] tmparr;
total = 0;
dict = graphdict; // snapshot
sgPatches = null;
if(dict != null && dict.size() > 0) {
if(attrname != null)
sgPatches = new Element[dict.size()];
n = 0;
enm = dict.elements();
while(enm.hasMoreElements()) {
sg = (Subgraph)enm.nextElement();
total += sg.prepPatchWork(attrname, mode);
if(attrname != null)
sgPatches[n++] = sg;
}
}
dict = nodedict; // snapshot;
elPatches = null;
if(attrname != null && dict != null && dict.size() > 0) {
m = 0;
n = 0;
if(mode <= 0)
elPatches = new Element[dict.size()];
else if(sgPatches == null)
elPatches = new Element[dict.size()];
else {
n = sgPatches.length;
elPatches = new Element[n + dict.size()];
System.arraycopy(sgPatches,0,elPatches,0,n);
sgPatches = null;
}
enm = dict.elements();
while(enm.hasMoreElements()) {
el = (Element)enm.nextElement();
if((obj = el.getAttributeValue(attrname)) != null) {
if(obj instanceof Number) {
el.setPatchSize(((Number)obj).doubleValue());
total += el.getPatchSize();
elPatches[n++] = el;
} else m++;
} else m++;
}
if(m > 0) {
if(n == m)
elPatches = null;
else {
tmparr = new Element[n-m];
System.arraycopy(elPatches,0,tmparr,0,tmparr.length);
elPatches = tmparr;
}
}
}
if(mode != 0) {
if(sgPatches != null)
Arrays.sort(sgPatches,0,sgPatches.length,this);
if(elPatches != null)
Arrays.sort(elPatches,0,elPatches.length,this);
}
setPatchSize(total);
return(total);
}
// squarified layout
double aspect(java.awt.geom.Rectangle2D.Double r) { return(r.getWidth() == 0 ? 1 : r.getHeight()/r.getWidth()); }
double score(double wd, double ht) { return((ht <= PATCHEDGE2 || wd <= PATCHEDGE2) ? Double.MAX_VALUE : (ht > wd ? (wd == 0 ? (ht == 0 ? 1 : Double.MAX_VALUE) : ht/wd) : (ht == 0 ? (wd == 0 ? 1 : Double.MAX_VALUE) : wd/ht))); }
public void computePatchWork(java.awt.geom.Rectangle2D.Double r, boolean square)
{
if(square)
compSqPatchWork(r, true);
else
compStdPatchWork(r, true);
}
private void compSqPatchWork(java.awt.geom.Rectangle2D.Double r, boolean top)
{
double frac;
double total;
double previous;
double next;
double tot;
double prv;
double nxt;
double dir;
java.awt.geom.Rectangle2D.Double box;
java.awt.geom.Rectangle2D.Double p;
java.awt.geom.Rectangle2D.Double pp;
Element el;
Attribute attr;
String style;
int i;
int j;
double pscore;
double nscore;
double sz;
double psz;
double tsz;
double tfrac;
setPatch(r);
setAttribute(MINSIZE_ATTR, new GrappaSize(r.getWidth(), r.getHeight()+(top?0:1)));
dir = aspect(r);
total = getPatchSize();
if(top)
box = new GrappaBox(r);
else
box = new GrappaBox(r.getX()+PATCHEDGE, r.getY()+PATCHEDGE, r.getWidth()-PATCHEDGE2, r.getHeight()-PATCHEDGE2);
if(dir > 1)
previous = box.getY();
else
previous = box.getX();
if(sgPatches != null) {
i = 0;
while(i < sgPatches.length) {
el = (Element)sgPatches[i];
sz = el.getPatchSize();
if((i+1) < sgPatches.length) {
psz = 0;
frac = sz / total;
if(dir > 1) {
pscore = score(box.getWidth(),frac*box.getHeight());
} else {
pscore = score(frac*box.getWidth(),box.getHeight());
}
j = i + 1;
for(;;) {
tsz = ((Element)sgPatches[j]).getPatchSize();
tot = psz + sz + tsz;
tfrac = tot / total;
if(dir > 1) {
nscore = score(box.getWidth() * sz / tot, tfrac*box.getHeight());
} else {
nscore = score(tfrac*box.getWidth(), box.getHeight() * sz / tot);
}
if(nscore <= pscore) {
if(dir > 1) {
pscore = score(box.getWidth() * tsz / tot, tfrac*box.getHeight());
} else {
pscore = score(tfrac*box.getWidth(), box.getHeight() * tsz / tot);
}
psz += sz;
sz = tsz;
tsz = 0;
j++;
if(j < sgPatches.length)
continue;
} else {
tsz = 0;
}
tot = psz + sz + tsz;
frac = tot / total;
if(dir > 1) {
prv = box.getX();
next = frac * box.getHeight();
} else {
prv = box.getY();
next = frac * box.getWidth();
}
for(; i < j; i++) {
el = (Element)sgPatches[i];
if(dir > 1) {
p = new GrappaBox(prv, previous, nxt = box.getWidth() * el.getPatchSize() / tot, next);
} else {
p = new GrappaBox(previous, prv, next, nxt = box.getHeight() * el.getPatchSize() / tot);
}
((Subgraph)el).compSqPatchWork(p, false);
prv += nxt;
}
break;
}
} else {
frac = sz / total;
if(dir > 1) {
p = new GrappaBox(box.getX(), previous, box.getWidth(), (next = frac * box.getHeight()));
} else {
p = new GrappaBox(previous, box.getY(), (next = frac * box.getWidth()), box.getHeight());
}
((Subgraph)el).compSqPatchWork(p, false);
i++;
}
previous += next;
}
}
if(elPatches != null) {
i = 0;
while(i < elPatches.length) {
el = (Element)elPatches[i];
sz = el.getPatchSize();
if((i+1) < elPatches.length) {
psz = 0;
frac = sz / total;
if(dir > 1) {
pscore = score(box.getWidth(),frac*box.getHeight());
} else {
pscore = score(frac*box.getWidth(),box.getHeight());
}
j = i + 1;
for(;;) {
tsz = ((Element)elPatches[j]).getPatchSize();
tot = psz + sz + tsz;
tfrac = tot / total;
if(dir > 1) {
nscore = score(box.getWidth() * sz / tot, tfrac*box.getHeight());
} else {
nscore = score(tfrac*box.getWidth(), box.getHeight() * sz / tot);
}
if(nscore <= pscore) {
if(dir > 1) {
pscore = score(box.getWidth() * tsz / tot, tfrac*box.getHeight());
} else {
pscore = score(tfrac*box.getWidth(), box.getHeight() * tsz / tot);
}
psz += sz;
sz = tsz;
tsz = 0;
j++;
if(j < elPatches.length)
continue;
} else {
tsz = 0;
}
tot = psz + sz + tsz;
frac = tot / total;
if(dir > 1) {
prv = box.getX();
next = frac * box.getHeight();
} else {
prv = box.getY();
next = frac * box.getWidth();
}
for(; i < j; i++) {
el = (Element)elPatches[i];
if(el instanceof Node) {
if(dir > 1) {
el.setPatch(prv, previous, nxt = box.getWidth() * el.getPatchSize() / tot, next);
} else {
el.setPatch(previous, prv, next, nxt = box.getHeight() * el.getPatchSize() / tot);
}
p = el.getPatch();
el.setAttribute(POS_ATTR, new GrappaPoint(p.getCenterX(), -p.getCenterY()));
el.setAttribute(WIDTH_ATTR, new Double(p.getWidth()/72.0));
el.setAttribute(HEIGHT_ATTR, new Double(p.getHeight()/72.0));
if (el.getLocalAttribute(COLOR_ATTR) == null)
el.setAttribute(COLOR_ATTR,”white”);
attr = el.getAttribute(STYLE_ATTR);
if(attr == null) {
el.setAttribute(STYLE_ATTR, “filled,lineColor(black)”);
} else {
style = attr.getStringValue();
el.setAttribute(STYLE_ATTR,style == null || style.length() == 0 ? “filled,lineColor(black)” : style + “,filled,lineColor(black)”);
}
} else {
if(dir > 1) {
p = new GrappaBox(prv, previous, nxt = box.getWidth() * el.getPatchSize() / tot, next);
} else {
p = new GrappaBox(previous, prv, next, nxt = box.getHeight() * el.getPatchSize() / tot);
}
((Subgraph)el).compSqPatchWork(p, false);
}
prv += nxt;
}
break;
}
} else {
frac = sz / total;
if(el instanceof Node) {
if(dir > 1) {
el.setPatch(box.getX(), previous, box.getWidth(), (next = frac * box.getHeight()));
} else {
el.setPatch(previous, box.getY(), (next = frac * box.getWidth()), box.getHeight());
}
p = el.getPatch();
el.setAttribute(POS_ATTR, new GrappaPoint(p.getCenterX(), -p.getCenterY()));
el.setAttribute(WIDTH_ATTR, new Double(p.getWidth()/72.0));
el.setAttribute(HEIGHT_ATTR, new Double(p.getHeight()/72.0));
if (el.getLocalAttribute(COLOR_ATTR) == null)
el.setAttribute(COLOR_ATTR,”white”);
attr = el.getAttribute(STYLE_ATTR);
if(attr == null) {
el.setAttribute(STYLE_ATTR, “filled,lineColor(black)”);
} else {
style = attr.getStringValue();
el.setAttribute(STYLE_ATTR,style == null || style.length() == 0 ? “filled,lineColor(black)” : style + “,filled,lineColor(black)”);
}
} else {
if(dir > 1) {
p = new GrappaBox(box.getX(), previous, box.getWidth(), (next = frac * box.getHeight()));
} else {
p = new GrappaBox(previous, box.getY(), (next = frac * box.getWidth()), box.getHeight());
}
((Subgraph)el).compSqPatchWork(p, false);
}
i++;
}
previous += next;
}
}
}
private void compStdPatchWork(java.awt.geom.Rectangle2D.Double r, boolean top)
{
double sz;
double frac;
double total;
double previous;
double next;
double dir;
java.awt.geom.Rectangle2D.Double box;
java.awt.geom.Rectangle2D.Double p;
Element el;
Attribute attr;
String style;
setPatch(r);
setAttribute(MINSIZE_ATTR, new GrappaSize(r.getWidth(), r.getHeight()+(top?0:1)));
dir = aspect(r);
total = getPatchSize();
if(top)
box = new GrappaBox(r);
else
box = new GrappaBox(r.getX()+PATCHEDGE, r.getY()+PATCHEDGE, r.getWidth()-PATCHEDGE2, r.getHeight()-PATCHEDGE2);
if(dir > 1)
previous = box.getY();
else
previous = box.getX();
if(sgPatches != null) {
for(int i = 0; i < sgPatches.length; i++) {
el = (Element)sgPatches[i];
sz = el.getPatchSize();
frac = sz / total;
if(dir > 1) {
((Subgraph)el).compStdPatchWork(new GrappaBox(box.getX(), previous, box.getWidth(), (next = frac * box.getHeight())), false);
} else {
((Subgraph)el).compStdPatchWork(new GrappaBox(previous, box.getY(), (next = frac * box.getWidth()), box.getHeight()), false);
}
previous += next;
}
}
if(elPatches != null) {
for(int i = 0; i < elPatches.length; i++) {
el = (Element)elPatches[i];
sz = el.getPatchSize();
frac = sz / total;
if(el instanceof Node) {
if(dir > 1) {
el.setPatch(box.getX(), previous, box.getWidth(), (next = frac * box.getHeight()));
} else {
el.setPatch(previous, box.getY(), (next = frac * box.getWidth()), box.getHeight());
}
p = el.getPatch();
el.setAttribute(POS_ATTR, new GrappaPoint(p.getCenterX(), -p.getCenterY()));
el.setAttribute(WIDTH_ATTR, new Double(p.getWidth()/72.0));
el.setAttribute(HEIGHT_ATTR, new Double(p.getHeight()/72.0));
if (el.getLocalAttribute(COLOR_ATTR) == null)
el.setAttribute(COLOR_ATTR,”white”);
attr = el.getAttribute(STYLE_ATTR);
if(attr == null) {
el.setAttribute(STYLE_ATTR, “filled,lineColor(black)”);
} else {
style = attr.getStringValue();
el.setAttribute(STYLE_ATTR,style == null || style.length() == 0 ? “filled,lineColor(black)” : style + “,filled,lineColor(black)”);
}
} else {
if(dir > 1) {
((Subgraph)el).compStdPatchWork(new GrappaBox(box.getX(), previous, box.getWidth(), (next = frac * box.getHeight())), false);
} else {
((Subgraph)el).compStdPatchWork(new GrappaBox(previous, box.getY(), (next = frac * box.getWidth()), box.getHeight()), false);
}
}
previous += next;
}
}
}
// Comparator for patchArea
public int compare(Object o1, Object o2) {
if(o1 instanceof Element) {
if(o2 instanceof Element) {
// biggest to smallest
double diff = ((Element)o2).getPatchSize() – ((Element)o1).getPatchSize();
return(diff < 0 ? -1 : diff > 0 ? 1 : 0);
} else return(0);
} else return(0);
}
public boolean equals(Object obj) {
// do not need
return(false);
}
//
// End PatchWork stuff
//
/**
* Get an enumeration of the node elements in this subgraph.
*
* @return an Enumeration of Node objects
*/
public Enumeration nodeElements() {
if(nodedict == null) {
return Grappa.emptyEnumeration.elements();
}
return nodedict.elements();
}
/**
* Get an enumeration of the edge elements in this subgraph.
*
* @return an Enumeration of Edge objects
*/
public Enumeration edgeElements() {
if(edgedict == null) {
return Grappa.emptyEnumeration.elements();
}
return edgedict.elements();
}
/**
* Get an enumeration of the subgraph elements in this subgraph.
*
* @return an Enumeration of Subgraph objects
*/
public Enumeration subgraphElements() {
if(graphdict == null) {
return Grappa.emptyEnumeration.elements();
}
return graphdict.elements();
}
/**
* Get an enumeration of elements in this subgraph and any subgraphs under this one.
*
* @param types a bitwise-oring of NODE, EDGE, SUBGRAPH to
* determine which element types should be in the enumeration
* @return a GraphEnumeration containing Element objects.
* @see GrappaConstants#NODE
* @see GrappaConstants#EDGE
* @see GrappaConstants#SUBGRAPH
*/
public GraphEnumeration elements(int types) {
return new Enumerator(types);
}
/**
* Get an enumeration of all elements in this subgraph and any subgraphs under this one.
* A convenience method equivalent to:
*
* elements(NODE|EDGE|SUBGRAPH)
*
*
* @return a GraphEnumeration containing Element objects.
* @see Subgraph#elements(int)
*/
public GraphEnumeration elements() {
return new Enumerator(NODE|EDGE|SUBGRAPH);
}
class Enumerator implements GraphEnumeration {
private Subgraph root = null;
private int types = 0;
private Enumeration enm = null;
private GraphEnumeration subEnum = null;
private Element elem = null;
private int dictType = 0;
Enumerator(int t) {
root = Subgraph.this;
types = t;
if((types&SUBGRAPH) != 0) {
elem = (Element)(root);
} else {
elem = null;
}
enm = subgraphElements();
if(enm.hasMoreElements()) {
dictType = SUBGRAPH;
while(enm.hasMoreElements()) {
subEnum = ((Subgraph)(enm.nextElement())).new Enumerator(types);
if(subEnum.hasMoreElements()) {
if(elem == null) {
elem = (Element)subEnum.nextElement();
}
break;
}
}
} else {
dictType = 0;
enm = null;
subEnum = null;
}
if(enm == null) {
if((types&NODE) != 0 && (enm = nodeElements()).hasMoreElements()) {
dictType = NODE;
if(elem == null) {
elem = (Element)enm.nextElement();
}
} else if((types&EDGE) != 0 && (enm = edgeElements()).hasMoreElements()) {
dictType = EDGE;
if(elem == null) {
elem = (Element)enm.nextElement();
}
} else {
enm = null;
}
}
}
public boolean hasMoreElements() {
return elem != null;
}
public Object nextElement() {
if(elem == null) {
throw new NoSuchElementException(“Subgraph$Enumerator”);
}
Element el = elem;
if(subEnum != null && subEnum.hasMoreElements()) {
elem = (Element)subEnum.nextElement();
} else if(enm != null && enm.hasMoreElements()) {
do {
elem = (Element)enm.nextElement();
if(elem.isSubgraph()) {
subEnum = ((Subgraph)elem).new Enumerator(getEnumerationTypes());
if(subEnum.hasMoreElements()) {
elem = (Element)subEnum.nextElement();
break;
} else {
elem = null;
}
} else {
break;
}
} while(enm.hasMoreElements());
} else {
elem = null;
}
if(elem == null) {
if(dictType != 0) {
if(dictType == SUBGRAPH) {
if((getEnumerationTypes()&NODE) != 0 && (enm = nodeElements()).hasMoreElements()) {
dictType = NODE;
elem = (Element)enm.nextElement();
} else if((getEnumerationTypes()&EDGE) != 0 && (enm = edgeElements()).hasMoreElements()) {
dictType = EDGE;
elem = (Element)enm.nextElement();
} else {
dictType = 0;
enm = null;
}
} else if(dictType == NODE) {
if((getEnumerationTypes()&EDGE) != 0 && (enm = edgeElements()).hasMoreElements()) {
dictType = EDGE;
elem = (Element)enm.nextElement();
} else {
dictType = 0;
enm = null;
}
} else {
dictType = 0;
enm = null;
}
}
}
return el;
}
public Element nextGraphElement() {
return (Element)nextElement();
}
public Subgraph getSubgraphRoot() {
return root;
}
public int getEnumerationTypes() {
return types;
}
}
/**
* Get a vector of elements in this subgraph and, by recursion, descendant
* subgraphs.
*
* @param types a bitwise-oring of NODE, EDGE, SUBGRAPH to
* determine which element types should be in the count
* @return a vector of the specified elements in this subgraph and its descendants (excluding the current subgraph itself).
* @see GrappaConstants#NODE
* @see GrappaConstants#EDGE
* @see GrappaConstants#SUBGRAPH
*/
public Vector vectorOfElements(int types) {
Vector retVec = new Vector();
int count = 0;
Enumeration elems = null;
if((types&NODE) != 0 && nodedict != null) {
count += nodedict.size();
retVec.ensureCapacity(count);
elems = nodedict.elements();
while(elems.hasMoreElements()) {
retVec.addElement(elems.nextElement());
}
}
if((types&EDGE) != 0 && edgedict != null) {
count += edgedict.size();
retVec.ensureCapacity(count);
elems = edgedict.elements();
while(elems.hasMoreElements()) {
retVec.addElement(elems.nextElement());
}
}
if(graphdict != null) {
if((types&SUBGRAPH) != 0) {
count += graphdict.size();
retVec.ensureCapacity(count);
}
elems = graphdict.elements();
while(elems.hasMoreElements()) {
((Subgraph)(elems.nextElement())).recurseVectorOfElements(types,retVec,count);
}
}
return(retVec);
}
// used above
void recurseVectorOfElements(int types, Vector retVec, int count) {
if((types&SUBGRAPH) != 0) retVec.addElement(this);
Enumeration elems = null;
if((types&NODE) != 0 && nodedict != null) {
count += nodedict.size();
retVec.ensureCapacity(count);
elems = nodedict.elements();
while(elems.hasMoreElements()) {
retVec.addElement(elems.nextElement());
}
}
if((types&EDGE) != 0 && edgedict != null) {
count += edgedict.size();
retVec.ensureCapacity(count);
elems = edgedict.elements();
while(elems.hasMoreElements()) {
retVec.addElement(elems.nextElement());
}
}
if(graphdict != null) {
if((types&SUBGRAPH) != 0) {
count += graphdict.size();
retVec.ensureCapacity(count);
}
elems = graphdict.elements();
while(elems.hasMoreElements()) {
((Subgraph)(elems.nextElement())).recurseVectorOfElements(types,retVec,count);
}
}
}
}
att/grappa/Symbols.java
att/grappa/Symbols.java
//—————————————————-
// The following code was generated by CUP v0.10k
// Wed May 25 19:10:51 EDT 2005
//—————————————————-
package att.grappa;
/** CUP generated class containing symbol constants. */
public class Symbols {
/* terminals */
public static final int SUBGRAPH = 5;
public static final int DIGRAPH = 9;
public static final int RBR = 17;
public static final int EQUAL = 18;
public static final int D_EDGE_OP = 6;
public static final int SEMI = 12;
public static final int STRICTDIGRAPH = 11;
public static final int ATSIGN = 20;
public static final int COLON = 19;
public static final int ATOM = 21;
public static final int RCUR = 15;
public static final int STRICT = 8;
public static final int COMMA = 13;
public static final int LCUR = 14;
public static final int EOF = 0;
public static final int ND_EDGE_OP = 7;
public static final int EDGE = 4;
public static final int GRAPH = 2;
public static final int error = 1;
public static final int LBR = 16;
public static final int STRICTGRAPH = 10;
public static final int NODE = 3;
/* non terminals */
static final int graphType = 2;
static final int optAttr = 20;
static final int attrAssignment = 29;
static final int graph = 9;
static final int hdr = 10;
static final int graphAttrDefs = 25;
static final int edge_op = 31;
static final int optSeparator = 17;
static final int optSemi = 16;
static final int NT$2 = 34;
static final int NT$1 = 33;
static final int NT$0 = 32;
static final int optStmtList = 12;
static final int $START = 0;
static final int subgraph = 22;
static final int optGraphName = 6;
static final int body = 11;
static final int optSubgHdr = 5;
static final int attrList = 24;
static final int attrItem = 28;
static final int node = 23;
static final int rCompound = 3;
static final int attrStmt = 15;
static final int simple = 19;
static final int optAttrDefs = 26;
static final int optStrict = 1;
static final int attrMacro = 30;
static final int optMacroName = 7;
static final int attrDefs = 27;
static final int optPort = 8;
static final int compound = 18;
static final int nodeList = 21;
static final int stmt = 14;
static final int attrType = 4;
static final int stmtList = 13;
}
Attribute
package att.grappa;
public final synchronized class Attribute extends java.util.Observable implements AttributeHandler, GrappaConstants {
private static AttributeHandler specialHandler;
private String name;
private String stringValue;
private Object value;
private int elementType;
private int attributeType;
private int nameHash;
public static AttributeHandler setAttributeHandler(AttributeHandler);
public void Attribute(int, String, Object);
public void Attribute(Attribute);
public final int getElementType();
public final int getAttributeType();
public final String getName();
public final Object getValue();
public final String getStringValue();
public final Object setValue(Object);
public final boolean equals(Attribute);
public final boolean equalsValue(Attribute);
public final int getNameHash();
public final void setChanged();
public final void clearChanged();
public String toString();
public String convertValue(int, String, Object, int);
public Object convertStringValue(int, String, String, int);
public Object copyValue(int, String, Object, int);
public static int attributeType(int, String);
static void
}
AttributeHandler
package att.grappa;
public abstract interface AttributeHandler {
public abstract String convertValue(int, String, Object, int);
public abstract Object convertStringValue(int, String, String, int);
public abstract Object copyValue(int, String, Object, int);
}
GrappaConstants
package att.grappa;
public abstract interface GrappaConstants {
public static final String PACKAGE_PREFIX = att.grappa.;
public static final String PKG_UPLOW = Grappa;
public static final String PKG_UPPER = GRAPPA;
public static final String PKG_LOWER = grappa;
public static final String NEW_LINE;
public static final char NBSP = 160;
public static final java.awt.geom.AffineTransform IDENTXFRM;
public static final int NODE = 1;
public static final int EDGE = 2;
public static final int SUBGRAPH = 4;
public static final int SYSTEM = 8;
public static final double LOG10;
public static final int SELECTION_MASK = 1;
public static final int DELETION_MASK = 2;
public static final int HIGHLIGHT_MASK = 3;
public static final int HIGHLIGHT_ON = 4;
public static final int HIGHLIGHT_OFF = 8;
public static final int HIGHLIGHT_TOGGLE = 16;
public static final int TYPES_SHIFT = 3;
public static final double PointsPerInch = 72.0;
public static final int PERIPHERY_GAP = 4;
public static final String ANONYMOUS_PREFIX = _anonymous_;
public static final String BBOX_ATTR = bb;
public static final String CLUSTERRANK_ATTR = clusterrank;
public static final String COLOR_ATTR = color;
public static final String CUSTOM_ATTR = custom;
public static final String DIR_ATTR = dir;
public static final String DISTORTION_ATTR = distortion;
public static final String FILLCOLOR_ATTR = fillcolor;
public static final String FONTCOLOR_ATTR = fontcolor;
public static final String FONTNAME_ATTR = fontname;
public static final String FONTSIZE_ATTR = fontsize;
public static final String FONTSTYLE_ATTR = fontstyle;
public static final String GRAPPA_BACKGROUND_COLOR_ATTR = grappaBackgroundColor;
public static final String GRAPPA_SELECTION_STYLE_ATTR = grappaSelectionColor;
public static final String GRAPPA_DELETION_STYLE_ATTR = grappaDeletionColor;
public static final String GRAPPA_FONTSIZE_ADJUSTMENT_ATTR = grappaFontsizeAdjustment;
public static final String HEIGHT_ATTR = height;
public static final String IMAGE_ATTR = image;
public static final String LABEL_ATTR = label;
public static final String LP_ATTR = lp;
public static final String HEADLABEL_ATTR = headlabel;
public static final String HEADLP_ATTR = head_lp;
public static final String TAILLABEL_ATTR = taillabel;
public static final String TAILLP_ATTR = tail_lp;
public static final String MARGIN_ATTR = margin;
public static final String MCLIMIT_ATTR = mclimit;
public static final String MINBOX_ATTR = minbox;
public static final String MINLEN_ATTR = minlen;
public static final String MINSIZE_ATTR = minsize;
public static final String NODESEP_ATTR = nodesep;
public static final String ORIENTATION_ATTR = orientation;
public static final String PATCH_ATTR = patch;
public static final String PERIPHERIES_ATTR = peripheries;
public static final String POS_ATTR = pos;
public static final String PRINTLIST_ATTR = printlist;
public static final String RANKDIR_ATTR = rankdir;
public static final String RANKSEP_ATTR = ranksep;
public static final String RECTS_ATTR = rects;
public static final String ROTATION_ATTR = rotation;
public static final String SHAPE_ATTR = shape;
public static final String SIDES_ATTR = sides;
public static final String SIZE_ATTR = size;
public static final String SKEW_ATTR = skew;
public static final String STYLE_ATTR = style;
public static final String TAG_ATTR = tag;
public static final String TIP_ATTR = tip;
public static final String WEIGHT_ATTR = weight;
public static final String WIDTH_ATTR = width;
public static final int BBOX_HASH;
public static final int COLOR_HASH;
public static final int CUSTOM_HASH;
public static final int DIR_HASH;
public static final int DISTORTION_HASH;
public static final int FILLCOLOR_HASH;
public static final int FONTCOLOR_HASH;
public static final int FONTNAME_HASH;
public static final int FONTSIZE_HASH;
public static final int FONTSTYLE_HASH;
public static final int GRAPPA_BACKGROUND_COLOR_HASH;
public static final int GRAPPA_SELECTION_STYLE_HASH;
public static final int GRAPPA_DELETION_STYLE_HASH;
public static final int GRAPPA_FONTSIZE_ADJUSTMENT_HASH;
public static final int HEIGHT_HASH;
public static final int IMAGE_HASH;
public static final int LABEL_HASH;
public static final int LP_HASH;
public static final int HEADLABEL_HASH;
public static final int HEADLP_HASH;
public static final int TAILLABEL_HASH;
public static final int TAILLP_HASH;
public static final int MARGIN_HASH;
public static final int MCLIMIT_HASH;
public static final int MINBOX_HASH;
public static final int MINLEN_HASH;
public static final int MINSIZE_HASH;
public static final int NODESEP_HASH;
public static final int ORIENTATION_HASH;
public static final int PATCH_HASH;
public static final int PERIPHERIES_HASH;
public static final int POS_HASH;
public static final int PRINTLIST_HASH;
public static final int RANKDIR_HASH;
public static final int RANKSEP_HASH;
public static final int RECTS_HASH;
public static final int ROTATION_HASH;
public static final int SHAPE_HASH;
public static final int SIDES_HASH;
public static final int SIZE_HASH;
public static final int SKEW_HASH;
public static final int STYLE_HASH;
public static final int TAG_HASH;
public static final int TIP_HASH;
public static final int WEIGHT_HASH;
public static final int WIDTH_HASH;
public static final int _NO_TYPE = 0;
public static final int BOX_TYPE = 1;
public static final int COLOR_TYPE = 2;
public static final int DIR_TYPE = 3;
public static final int DOUBLE_TYPE = 4;
public static final int FONTSTYLE_TYPE = 5;
public static final int HASHLIST_TYPE = 6;
public static final int INTEGER_TYPE = 7;
public static final int LINE_TYPE = 8;
public static final int POINT_TYPE = 9;
public static final int SHAPE_TYPE = 10;
public static final int SIZE_TYPE = 11;
public static final int STRING_TYPE = 12;
public static final int STYLE_TYPE = 13;
public static final int NO_SHAPE = 0;
public static final int LINE_SHAPE = 1;
public static final int BOX_SHAPE = 2;
public static final int DIAMOND_SHAPE = 3;
public static final int DOUBLECIRCLE_SHAPE = 4;
public static final int DOUBLEOCTAGON_SHAPE = 5;
public static final int EGG_SHAPE = 6;
public static final int HEXAGON_SHAPE = 7;
public static final int HOUSE_SHAPE = 8;
public static final int INVERTEDHOUSE_SHAPE = 9;
public static final int INVERTEDTRAPEZIUM_SHAPE = 10;
public static final int INVERTEDTRIANGLE_SHAPE = 11;
public static final int OCTAGON_SHAPE = 12;
public static final int OVAL_SHAPE = 13;
public static final int PARALLELOGRAM_SHAPE = 14;
public static final int PENTAGON_SHAPE = 15;
public static final int PLAINTEXT_SHAPE = 16;
public static final int POINT_SHAPE = 17;
public static final int POLYGON_SHAPE = 18;
public static final int RECORD_SHAPE = 19;
public static final int ROUNDEDBOX_SHAPE = 20;
public static final int TRAPEZIUM_SHAPE = 21;
public static final int TRIANGLE_SHAPE = 22;
public static final int TRIPLEOCTAGON_SHAPE = 23;
public static final int MCIRCLE_SHAPE = 24;
public static final int MDIAMOND_SHAPE = 25;
public static final int MRECORD_SHAPE = 26;
public static final int MSQUARE_SHAPE = 27;
public static final int CUSTOM_SHAPE = 28;
public static final int SHAPE_MASK = 1023;
public static final int GRAPPA_SHAPE = 1024;
static void
}
CustomRenderer
package att.grappa;
public abstract interface CustomRenderer {
public abstract void draw(java.awt.Graphics2D);
public abstract void fill(java.awt.Graphics2D);
public abstract void drawImage(java.awt.Graphics2D);
}
Edge$Enumerator
package att.grappa;
synchronized class Edge$Enumerator implements java.util.Enumeration {
Node node1;
Node node2;
Edge next;
java.util.Enumeration outEdges;
java.util.Enumeration inEdges;
void Edge$Enumerator(Node, Node);
private Edge getNext();
public boolean hasMoreElements();
public Object nextElement();
}
Edge
package att.grappa;
public synchronized class Edge extends Element {
public static final String defaultNamePrefix = E;
private Node headNode;
private String headPortId;
private Node tailNode;
private String tailPortId;
private String key;
int direction;
public void Edge(Subgraph, Node, Node);
public void Edge(Subgraph, Node, String, Node, String);
public void Edge(Subgraph, Node, String, Node, String, String) throws RuntimeException;
public void Edge(Subgraph, Node, Node, String) throws RuntimeException;
public void Edge(Subgraph, Node, String, Node, String, String, String) throws RuntimeException;
private void edgeAttrsOfInterest();
public static Edge findEdgeByKey(Node, Node, String);
public boolean isEdge();
public int getType();
void setName();
public String getKey();
public Node getHead();
public String getHeadPortId();
public Node getTail();
public String getTailPortId();
public String toString();
public void printEdge(java.io.PrintWriter);
public boolean goesForward();
public boolean goesReverse();
public static int attributeType(String);
public static java.util.Enumeration findEdgesByEnds(Node, Node);
}
Element
package att.grappa;
public abstract synchronized class Element implements GrappaConstants {
private Graph graph;
private Subgraph subgraph;
long visastamp;
private boolean deleteCalled;
private boolean busy;
private static java.util.Hashtable userAttributeTypeMap;
public Object object;
public boolean visible;
public boolean selectable;
public int linewidth;
public static boolean usePrintList;
public int counter;
public int highlight;
private Long idKey;
String name;
java.util.Hashtable attributes;
java.util.Hashtable attrsOfInterest;
GrappaNexus grappaNexus;
public boolean printAllAttributes;
public boolean printDefaultAttributes;
String canonName;
private double patchSize;
private java.awt.geom.Rectangle2D$Double patch;
protected void Element();
protected void Element(int, Subgraph);
private void elementAttrsOfInterest();
public abstract int getType();
public boolean isNode();
public boolean isEdge();
public boolean isSubgraph();
abstract void setName();
public String getName();
boolean reserve();
void release();
boolean setDelete(boolean);
private synchronized boolean setReserved(boolean, boolean);
protected void attrOfInterest(String);
protected void attrNotOfInterest(String);
public java.util.Enumeration listAttrsOfInterest();
public boolean isOfInterest(String);
public Object setAttribute(Attribute);
public Object setAttribute(String, Object);
private Attribute removeAttribute(String);
public Object setDefaultAttribute(String, Object);
public Object setDefaultAttribute(int, String, Object);
public Object setDefaultAttribute(Attribute);
public Object setDefaultAttribute(int, Attribute);
public java.util.Enumeration getLocalAttributeKeys();
public java.util.Enumeration getLocalAttributePairs();
public java.util.Enumeration getAttributePairs();
public Attribute getLocalAttribute(String);
public Attribute getThisAttribute(String);
public Object getThisAttributeValue(String);
public Attribute getDefaultAttribute(int, String);
public Attribute getDefaultAttribute(String);
public Attribute getAttribute(String);
public Object getAttributeValue(String);
public boolean hasAttributeForKey(String);
public Graph getGraph();
public Subgraph getSubgraph();
void setGraph(Graph);
public void setSubgraph(Subgraph);
protected void clearBBox();
public int getId();
public Long getIdKey();
protected void setIdKey(int);
public void printElement(java.io.PrintWriter);
private void printAttributes(java.io.PrintWriter, String);
public String toString();
public static String canonString(String);
public static final String typeString(int, boolean);
public static String canonValue(String);
boolean deleteCalled();
public final boolean delete();
public void addTag(String);
public boolean hasTag(String);
public boolean hasLocalTag(String);
public boolean hasDefaultTag(String);
public boolean hasTags();
public boolean hasLocalTags();
public boolean hasDefaultTags();
public void removeTags();
public void removeTag(String);
public static int setUserAttributeType(String, int);
public static int attributeType(String);
public void buildShape();
public GrappaNexus getGrappaNexus();
public java.util.Vector bdfs(int);
private static void doBDFS(int, int, long, int, java.util.Vector, java.util.Vector);
double getPatchSize();
void setPatchSize(double);
java.awt.geom.Rectangle2D$Double getPatch();
void setPatch(java.awt.geom.Rectangle2D$Double);
void setPatch(double, double, double, double);
static void
}
Node$Enumerator
package att.grappa;
synchronized class Node$Enumerator implements java.util.Enumeration {
int inCnt;
int outCnt;
java.util.Vector inEdges;
java.util.Vector outEdges;
void Node$Enumerator(Node, java.util.Vector, java.util.Vector);
public boolean hasMoreElements();
public Object nextElement();
}
Node
package att.grappa;
public synchronized class Node extends Element {
public static final String defaultNamePrefix = N;
private java.util.Vector inEdges;
private java.util.Vector outEdges;
private java.util.Vector Ports;
public void Node(Subgraph, String);
public void Node(Subgraph);
private void nodeAttrsOfInterest();
public boolean isNode();
public int getType();
void setName();
public void setName(String) throws IllegalArgumentException;
private void resetEdgeNames();
public synchronized void addEdge(Edge, boolean);
public Edge findOutEdgeByKey(Node, String);
public Edge findInEdgeByKey(Node, String);
public GrappaPoint getCenterPoint();
public synchronized void removeEdge(Edge, boolean);
public void printNode(java.io.PrintWriter);
public static int attributeType(String);
public java.util.Enumeration edgeElements();
public java.util.Enumeration inEdgeElements();
public java.util.Enumeration outEdgeElements();
}
Subgraph$Enumerator
package att.grappa;
synchronized class Subgraph$Enumerator implements GraphEnumeration {
private Subgraph root;
private int types;
private java.util.Enumeration enm;
private GraphEnumeration subEnum;
private Element elem;
private int dictType;
void Subgraph$Enumerator(Subgraph, int);
public boolean hasMoreElements();
public Object nextElement();
public Element nextGraphElement();
public Subgraph getSubgraphRoot();
public int getEnumerationTypes();
}
Subgraph
package att.grappa;
public synchronized class Subgraph extends Element implements java.util.Comparator {
public static final String defaultNamePrefix = G;
private java.util.Hashtable nodedict;
private java.util.Hashtable edgedict;
private java.util.Hashtable graphdict;
private boolean nodeLabels;
private boolean edgeLabels;
private boolean subgLabels;
private java.util.Hashtable nodeAttributes;
private java.util.Hashtable edgeAttributes;
private boolean cluster;
public Object currentSelection;
private double PATCHEDGE;
private double PATCHEDGE2;
private Element[] sgPatches;
private Element[] elPatches;
private GrappaBox patch;
void Subgraph();
public void Subgraph(Subgraph, String);
public void Subgraph(Subgraph);
private void subgraphAttrsOfInterest();
public boolean isSubgraph();
public int getType();
void setName();
public void setName(String) throws IllegalArgumentException;
public boolean isCluster();
public boolean isRoot();
public Attribute getNodeAttribute(String);
public Object getNodeAttributeValue(String);
public java.util.Enumeration getNodeAttributeKeys();
public java.util.Enumeration getNodeAttributePairs();
public Object setNodeAttribute(Attribute);
public Object setNodeAttribute(String, Object);
private void removeNodeAttribute(String);
public Object setEdgeAttribute(Attribute);
public Object setEdgeAttribute(String, Object);
private void removeEdgeAttribute(String);
public Object setAttribute(Attribute);
public Object setAttribute(String, Object);
public Attribute getEdgeAttribute(String);
public Object getEdgeAttributeValue(String);
public java.util.Enumeration getEdgeAttributeKeys();
public java.util.Enumeration getEdgeAttributePairs();
public java.awt.geom.Rectangle2D getBoundingBox();
public java.awt.geom.Rectangle2D resetBoundingBox();
public void printSubgraph(java.io.PrintWriter);
private void printDflt(java.io.PrintWriter, int);
private void printDfltAttr(java.io.PrintWriter, java.util.Hashtable, int, String, String);
public static int attributeType(String);
private Attribute getParentDefault(int, String);
private Element findElementByName(int, String);
private Element findElementInSubgraphByName(int, String);
public Node findNodeByName(String);
public Edge findEdgeByName(String);
public Subgraph findSubgraphByName(String);
public Element createElement(int, Object[], Attribute[]);
public void addNode(Node);
public Node removeNode(String);
public void addEdge(Edge);
public Edge removeEdge(String);
public void addSubgraph(Subgraph);
public Subgraph removeSubgraph(String);
public boolean setShowSubgraphLabels(boolean);
public boolean setShowNodeLabels(boolean);
public boolean setShowEdgeLabels(boolean);
public boolean getShowSubgraphLabels();
public boolean getShowNodeLabels();
public boolean getShowEdgeLabels();
public boolean isLR();
public void addTypeTag(int, String);
public boolean hasTypeTag(int, String);
public boolean hasTypeTags(int);
public void removeTypeTags(int);
public void removeTypeTag(int, String);
public int countOfLocalElements(int);
public int countOfElements(int);
public void removeEmptySubgraphs();
public boolean hasEmptySubgraphs();
public void clearPatchWork();
public void patchWork(java.awt.geom.Rectangle2D$Double, boolean, int);
public double preparePatchWork(int);
Element[] getPatches();
private void combPatchWork();
private double prepPatchWork(String, int);
double aspect(java.awt.geom.Rectangle2D$Double);
double score(double, double);
public void computePatchWork(java.awt.geom.Rectangle2D$Double, boolean);
private void compSqPatchWork(java.awt.geom.Rectangle2D$Double, boolean);
private void compStdPatchWork(java.awt.geom.Rectangle2D$Double, boolean);
public int compare(Object, Object);
public boolean equals(Object);
public java.util.Enumeration nodeElements();
public java.util.Enumeration edgeElements();
public java.util.Enumeration subgraphElements();
public GraphEnumeration elements(int);
public GraphEnumeration elements();
public java.util.Vector vectorOfElements(int);
void recurseVectorOfElements(int, java.util.Vector, int);
}
Graph
package att.grappa;
public synchronized class Graph extends Subgraph {
public static final String INDENT_STRING = ;
boolean filterMode;
private StringBuffer indent;
private java.io.PrintWriter errWriter;
private boolean paintCalled;
private boolean busy;
private boolean synchronizePaint;
private String toolTipText;
private java.util.List panelList;
private int gid;
private int nid;
private int eid;
private boolean editable;
private boolean menuable;
private boolean selectable;
private boolean directed;
private boolean strict;
java.util.Hashtable id2element;
private java.util.Hashtable grattributes;
private static java.util.Hashtable sysdfltNodeAttributes;
private static java.util.Hashtable sysdfltEdgeAttributes;
private static java.util.Hashtable sysdfltGraphAttributes;
public final java.awt.font.FontRenderContext REFCNTXT;
private static void putAttribute(java.util.Hashtable, int, String, String);
public void Graph(String, boolean, boolean);
public void Graph(String);
private void initialize(String);
private void setDirection(boolean);
public boolean setSynchronizePaint(boolean);
public boolean getSynchronizePaint();
public boolean dropcloth(boolean, boolean);
boolean setPaint(boolean);
private synchronized boolean setBlocked(boolean, boolean, boolean);
public Attribute getGrappaAttribute(String) throws IllegalArgumentException;
public Object getGrappaAttributeValue(String) throws IllegalArgumentException;
public Object setGrappaAttribute(String, String) throws IllegalArgumentException;
public static int attributeType(String);
public java.util.Enumeration getGrappaAttributeKeys();
public static boolean validGrappaAttributeKey(String);
public static Attribute getGlobalAttribute(int, String) throws IllegalArgumentException;
public static java.util.Enumeration getGlobalAttributeKeys(int) throws IllegalArgumentException;
public static java.util.Enumeration getGlobalAttributePairs(int) throws IllegalArgumentException;
public static int getGlobalAttributeSize(int) throws IllegalArgumentException;
Element addIdMapping(Element);
static Long idMapKey(int, int) throws IllegalArgumentException;
static int idKeyType(Long);
static int idKeyId(Long);
Element element4Id(Long);
void removeIdMapping(Element);
public void printGraph(java.io.Writer);
public void printGraph(java.io.OutputStream);
int nextId(int) throws IllegalArgumentException;
public int getId(int) throws IllegalArgumentException;
public String getIndent();
public void incrementIndent();
public void decrementIndent();
public boolean isDirected();
public boolean isStrict();
public String setToolTipText(String);
public String getToolTipText();
public void reset();
public void reset(String, boolean, boolean);
public boolean isEditable();
public boolean setEditable(boolean);
public boolean isSelectable();
public boolean setSelectable(boolean);
public boolean isMenuable();
public boolean setMenuable(boolean);
public java.io.PrintWriter setErrorWriter(java.io.PrintWriter);
public java.io.PrintWriter getErrorWriter();
public void printError(String);
public void printError(String, Exception);
public void buildShapes();
public void resync();
public void repaint();
public void paintImmediately();
public void addPanel(GrappaPanel);
public void removePanel(GrappaPanel);
static void
}
GrappaNexus
package att.grappa;
public synchronized class GrappaNexus implements GrappaConstants, Cloneable, java.awt.image.ImageObserver, java.util.Observer, java.awt.Shape {
public static double arcHeightFactor;
public static double arcWidthFactor;
java.awt.geom.Area textArea;
java.awt.Shape shape;
int shapeType;
java.awt.geom.Rectangle2D bbox;
GrappaStyle style;
java.awt.Color fillcolor;
java.awt.Color color;
java.awt.Image image;
boolean imageLoading;
boolean dirty;
java.awt.Stroke stroke;
private Object[] objs;
private Object custom_shape;
public boolean boundText;
public boolean clearText;
public boolean drawText;
Element element;
long lastUpdate;
private long lastShapeUpdate;
private long lastTextUpdate;
private long lastStyleUpdate;
private long lastDecorationUpdate;
private long lastImageUpdate;
java.awt.Font font;
String[] lstr;
GrappaPoint[] lpos;
java.awt.Color font_color;
private int windingRule;
public void GrappaNexus(Element);
public Element getElement();
public java.awt.Image getImage();
public boolean isImageLoading();
public int getWindingRule();
public void rebuild();
public void updateShape();
public void updateStyle();
public void updateText();
public void updateDecoration();
public void updateImage();
public final boolean imageUpdate(java.awt.Image, int, int, int, int, int);
private void bboxCheckSet();
public Object clone();
public boolean contains(double, double);
public boolean contains(double, double, double, double);
public boolean contains(java.awt.geom.Point2D);
public boolean contains(java.awt.geom.Rectangle2D);
public java.awt.Rectangle getBounds();
public java.awt.geom.Rectangle2D getBounds2D();
java.awt.geom.Rectangle2D rawBounds2D();
public java.awt.geom.PathIterator getPathIterator();
public java.awt.geom.PathIterator getPathIterator(java.awt.geom.AffineTransform);
public java.awt.geom.PathIterator getPathIterator(java.awt.geom.AffineTransform, double);
public boolean intersects(double, double, double, double);
public boolean intersects(java.awt.geom.Rectangle2D);
public void update(java.util.Observable, Object);
void draw(java.awt.Graphics2D);
void fill(java.awt.Graphics2D);
void drawImage(java.awt.Graphics2D);
static void
}
GrappaPoint
package att.grappa;
public synchronized class GrappaPoint extends java.awt.geom.Point2D$Double {
public void GrappaPoint();
public void GrappaPoint(double, double);
public void GrappaPoint(String);
public String toAttributeString();
public String toFormattedString(String);
public String toString();
}
GrappaBox
package att.grappa;
public synchronized class GrappaBox extends java.awt.geom.Rectangle2D$Double {
private boolean dimensioned;
public void GrappaBox();
public void GrappaBox(java.awt.geom.Rectangle2D);
public void GrappaBox(double, double, double, double);
public void GrappaBox(String, boolean);
public void GrappaBox(String);
public String toAttributeString();
public String toFormattedString(String);
public String toString();
public boolean isDimensioned();
}
GraphEnumeration
package att.grappa;
public abstract interface GraphEnumeration extends java.util.Enumeration {
public abstract Subgraph getSubgraphRoot();
public abstract int getEnumerationTypes();
public abstract Element nextGraphElement() throws java.util.NoSuchElementException;
}
GrappaPanel
package att.grappa;
public synchronized class GrappaPanel extends javax.swing.JPanel implements GrappaConstants, java.awt.event.ComponentListener, javax.swing.event.AncestorListener, javax.swing.event.PopupMenuListener, java.awt.event.MouseListener, java.awt.event.MouseMotionListener, java.awt.print.Printable, Runnable, javax.swing.Scrollable {
Graph graph;
Subgraph subgraph;
GrappaBacker backer;
boolean nodeLabels;
boolean edgeLabels;
boolean subgLabels;
java.awt.geom.AffineTransform transform;
java.awt.geom.AffineTransform oldTransform;
java.awt.geom.AffineTransform inverseTransform;
java.util.Vector elementVector;
int nextElement;
boolean scaleToFit;
GrappaSize scaleToSize;
GrappaListener grappaListener;
private Element pressedElement;
private GrappaPoint pressedPoint;
private int pressedModifiers;
private GrappaStyle selectionStyle;
private GrappaStyle deletionStyle;
private double scaleFactor;
private double scaleInfo;
private GrappaBox outline;
private GrappaBox savedOutline;
private GrappaBox zoomBox;
private boolean inMenu;
private boolean scaleChanged;
private boolean paintActive;
private java.awt.geom.Point2D panelcpt;
public void GrappaPanel(Subgraph);
public void GrappaPanel(Subgraph, GrappaBacker);
public GrappaListener addGrappaListener(GrappaListener);
public GrappaListener removeGrappaListener();
public int print(java.awt.Graphics, java.awt.print.PageFormat, int) throws java.awt.print.PrinterException;
public void paintComponent(java.awt.Graphics);
void setCPT(java.awt.geom.Point2D);
java.awt.geom.Point2D getCPT();
private java.awt.geom.Point2D componentPaint(java.awt.Graphics);
public void centerPanelAtPoint(java.awt.geom.Point2D);
public java.awt.geom.AffineTransform getTransform();
public java.awt.geom.AffineTransform getInverseTransform();
public void setToolTipText(String);
public String getToolTipText(java.awt.event.MouseEvent);
public void setScaleToFit(boolean);
public void setScaleToSize(java.awt.geom.Dimension2D);
public Subgraph getSubgraph();
public void resetZoom();
public boolean hasOutline();
public void clearOutline();
public GrappaBox zoomToOutline();
public GrappaBox zoomToOutline(GrappaBox);
public double multiplyScaleFactor(double);
private void paintSubgraph(java.awt.Graphics2D, Subgraph, java.awt.Shape, java.awt.Color);
private Element findContainingElement(Subgraph, java.awt.geom.Point2D);
private Element findContainingElement(Subgraph, java.awt.geom.Point2D, Element);
private Element reallyFindContainingElement(Subgraph, java.awt.geom.Point2D, Element[]);
public void ancestorMoved(javax.swing.event.AncestorEvent);
public void ancestorAdded(javax.swing.event.AncestorEvent);
public void ancestorRemoved(javax.swing.event.AncestorEvent);
public void componentHidden(java.awt.event.ComponentEvent);
public void componentMoved(java.awt.event.ComponentEvent);
public void componentResized(java.awt.event.ComponentEvent);
public void componentShown(java.awt.event.ComponentEvent);
public void popupMenuCanceled(javax.swing.event.PopupMenuEvent);
public void popupMenuWillBecomeInvisible(javax.swing.event.PopupMenuEvent);
public void popupMenuWillBecomeVisible(javax.swing.event.PopupMenuEvent);
public void mouseClicked(java.awt.event.MouseEvent);
public void mousePressed(java.awt.event.MouseEvent);
public void mouseReleased(java.awt.event.MouseEvent);
public void mouseEntered(java.awt.event.MouseEvent);
public void mouseExited(java.awt.event.MouseEvent);
public void mouseDragged(java.awt.event.MouseEvent);
public void mouseMoved(java.awt.event.MouseEvent);
public java.awt.Dimension getPreferredScrollableViewportSize();
public int getScrollableUnitIncrement(java.awt.Rectangle, int, int);
public int getScrollableBlockIncrement(java.awt.Rectangle, int, int);
public boolean getScrollableTracksViewportWidth();
public boolean getScrollableTracksViewportHeight();
public void run();
}
GrappaStyle
package att.grappa;
public synchronized class GrappaStyle implements GrappaConstants, Cloneable {
private int elementType;
public static final String DEFAULT_SET_STRING = __default__;
public static final int STYLE_SOLID = 0;
public static final int STYLE_DASHED = 1;
public static final int STYLE_DOTTED = 2;
public static final int STYLE_DASH = 3;
public static final int STYLE_DASH_PHASE = 4;
public static final int STYLE_LINE_WIDTH = 5;
public static final int STYLE_LINE_COLOR = 6;
public static final int STYLE_FILLED = 7;
public static final int STYLE_DIAGONALS = 8;
public static final int STYLE_ROUNDED = 9;
public static final int STYLE_CAP_BUTT = 10;
public static final int STYLE_CAP_ROUND = 11;
public static final int STYLE_CAP_SQUARE = 12;
public static final int STYLE_JOIN_BEVEL = 13;
public static final int STYLE_JOIN_MITER = 14;
public static final int STYLE_JOIN_ROUND = 15;
public static final int STYLE_MITER_LIMIT = 16;
public static final int STYLE_FIXED_SIZE = 17;
public static final int STYLE_INVIS = 18;
public static final int STYLE_OLD_BOLD = 100;
public static final int STYLE_OLD_ITALIC = 101;
public static final int STYLE_OLD_PLAIN = 102;
public static final java.awt.Color STYLE_LINE_COLOR_DEFAULT;
public static final int STYLE_LINE_STYLE_DEFAULT = 0;
public static final float STYLE_LINE_WIDTH_DEFAULT = 1.0;
public static final int STYLE_CAP_DEFAULT = 0;
public static final int STYLE_JOIN_DEFAULT = 2;
public static final float STYLE_MITER_LIMIT_DEFAULT = 0.0;
public static final float[] STYLE_DASH_DEFAULT;
public static final float STYLE_DASH_PHASE_DEFAULT = 0.0;
public static final boolean STYLE_ROUNDED_DEFAULT = 0;
public static final boolean STYLE_DIAGONALS_DEFAULT = 0;
public static final boolean STYLE_FILLED_DEFAULT = 0;
public static final boolean STYLE_INVIS_DEFAULT = 0;
public static final boolean STYLE_FIXED_SIZE_DEFAULT = 0;
static java.awt.BasicStroke defaultStroke;
static String defaultStrokeString;
private static java.util.Hashtable styleTypes;
private static java.util.Hashtable strokeCache;
java.awt.Color line_color;
int line_style;
float line_width;
int cap;
int join;
float miter_limit;
float[] dash;
float dash_phase;
boolean rounded;
boolean diagonals;
boolean filled;
boolean invis;
boolean fixed_size;
Integer font_style;
java.awt.BasicStroke stroke;
public void GrappaStyle(int, String);
public void updateStyle(String);
private static String generateStrokeString(float, int, int, float, float[], float);
public String toAttributeString();
public String toString();
private static String generateStyleString(java.awt.Color, int, float, int, int, float, float[], float, boolean, boolean, boolean, boolean, boolean, Integer, boolean, int);
public java.awt.Color getLineColor();
public int getLineStyle();
public float getLineWidth();
public int getCapStyle();
public int getJoinStyle();
public float getMiterLimit();
public float[] getDash();
public float getDashPhase();
public boolean getRounded();
public boolean getDiagonals();
public boolean getFilled();
public boolean getInvis();
public boolean getFixedSize();
public int getFontStyle();
public Object clone();
static void
}
GrappaBacker
package att.grappa;
public abstract interface GrappaBacker {
public abstract void drawBackground(java.awt.Graphics2D, Graph, java.awt.geom.Rectangle2D, java.awt.Shape);
}
GrappaSize
package att.grappa;
public synchronized class GrappaSize extends java.awt.geom.Dimension2D {
public double width;
public double height;
public void GrappaSize();
public void GrappaSize(double, double);
public void GrappaSize(String);
public double getWidth();
public double getHeight();
public void setSize(java.awt.geom.Dimension2D);
public void setSize(double, double);
public String toAttributeString();
public String toFormattedString(String);
public String toString();
}
GrappaListener
package att.grappa;
public abstract interface GrappaListener {
public abstract void grappaClicked(Subgraph, Element, GrappaPoint, int, int, GrappaPanel);
public abstract void grappaPressed(Subgraph, Element, GrappaPoint, int, GrappaPanel);
public abstract void grappaReleased(Subgraph, Element, GrappaPoint, int, Element, GrappaPoint, int, GrappaBox, GrappaPanel);
public abstract void grappaDragged(Subgraph, GrappaPoint, int, Element, GrappaPoint, int, GrappaBox, GrappaPanel);
public abstract String grappaTip(Subgraph, Element, GrappaPoint, int, GrappaPanel);
}
ExceptionDisplay$Display
package att.grappa;
synchronized class ExceptionDisplay$Display extends java.awt.Frame {
private java.awt.TextArea textarea;
private java.awt.Panel buttonPanel;
private java.awt.Button trace;
private java.awt.Button dismiss;
private ExceptionDisplay$Display$WindowObserver observer;
void ExceptionDisplay$Display(ExceptionDisplay, String);
void setText(String);
Exception getException();
}
ExceptionDisplay$Display$WindowObserver
package att.grappa;
synchronized class ExceptionDisplay$Display$WindowObserver extends java.awt.event.WindowAdapter implements java.awt.event.ActionListener {
void ExceptionDisplay$Display$WindowObserver(ExceptionDisplay$Display);
public void windowClosing(java.awt.event.WindowEvent);
private void dismiss();
public void actionPerformed(java.awt.event.ActionEvent);
}
ExceptionDisplay
package att.grappa;
public synchronized class ExceptionDisplay {
private String title;
Exception exception;
ExceptionDisplay$Display display;
public void ExceptionDisplay(String);
public void displayException(Exception);
public void displayException(Exception, String);
}
GraphParserException
package att.grappa;
public synchronized class GraphParserException extends RuntimeException {
public void GraphParserException();
public void GraphParserException(String);
}
Grappa
package att.grappa;
public abstract synchronized class Grappa implements GrappaConstants {
public static java.util.Hashtable keyToShape;
public static java.util.Hashtable shapeToKey;
public static java.awt.Toolkit toolkit;
private static final ExceptionDisplay exceptionDisplay;
public static boolean doDisplayException;
public static final java.util.Vector emptyEnumeration;
private static String toolTipText;
public static boolean elementPrintAllAttributes;
public static boolean elementPrintDefaultAttributes;
public static boolean shapeBoundText;
public static boolean shapeClearText;
public static boolean shapeDrawText;
public static boolean centerPointNodes;
public static boolean autoPositionNodeLabel;
public static boolean provideBBoxAttribute;
public static int windingRule;
public static boolean orientationInDegrees;
public static boolean rotationInDegrees;
public static boolean usePrintList;
public static boolean printVisibleOnly;
public static boolean useAntiAliasing;
public static boolean antiAliasText;
public static boolean useFractionalMetrics;
public static boolean negateStringYCoord;
public static boolean labelGraphBottom;
public static boolean labelGraphOutside;
public static boolean backgroundDrawing;
public static double nodeLabelsScaleCutoff;
public static boolean outlineSubgraphs;
public static double edgeLabelsScaleCutoff;
public static double subgLabelsScaleCutoff;
public static boolean synchronizePaint;
public static boolean waitForImages;
public static int elementSelection;
public void Grappa();
public static void displayException(Exception);
public static void displayException(Exception, String);
public static String setToolTipText(String);
public static String getToolTipText();
static void
}
GrappaAdapter
package att.grappa;
public synchronized class GrappaAdapter implements GrappaConstants, GrappaListener, java.awt.event.ActionListener {
public void GrappaAdapter();
public void grappaClicked(Subgraph, Element, GrappaPoint, int, int, GrappaPanel);
public void grappaPressed(Subgraph, Element, GrappaPoint, int, GrappaPanel);
public void grappaReleased(Subgraph, Element, GrappaPoint, int, Element, GrappaPoint, int, GrappaBox, GrappaPanel);
public void grappaDragged(Subgraph, GrappaPoint, int, Element, GrappaPoint, int, GrappaBox, GrappaPanel);
public String grappaTip(Subgraph, Element, GrappaPoint, int, GrappaPanel);
public void actionPerformed(java.awt.event.ActionEvent);
protected void drillDown(Subgraph, java.util.Vector, int, int);
}
GrappaColor
package att.grappa;
public abstract synchronized class GrappaColor {
private static java.util.Hashtable colorTable;
private static java.util.Hashtable colorLookUp;
public static final java.awt.Color defaultForeground;
public static final java.awt.Color defaultBackground;
public static final java.awt.Color defaultXOR;
public static final java.awt.Color defaultFontcolor;
public static final java.awt.Color defaultColor;
public void GrappaColor();
public static void addColor(String, java.awt.Color) throws IllegalArgumentException;
private static void doAddColor(String, java.awt.Color, boolean);
private static void doAddColor(String, java.awt.Color);
private static String canonColor(String, float[]);
public static java.awt.Color getColor(String, java.awt.Color);
public static String getColorName(java.awt.Color);
static void
}
GrappaLine
package att.grappa;
public synchronized class GrappaLine implements GrappaConstants, Cloneable, java.awt.Shape {
public static final double arrowLength = 10.0;
public static final double arrowWidth = 5.0;
public static final int NONE_ARROW_EDGE = 0;
public static final int HEAD_ARROW_EDGE = 1;
public static final int TAIL_ARROW_EDGE = 2;
public static final int BOTH_ARROW_EDGE = 3;
private java.awt.geom.GeneralPath path;
private java.awt.geom.GeneralPath testpath;
private int arrow;
private GrappaPoint[] gpts;
private int windingRule;
public void GrappaLine(GrappaPoint[], int);
public void GrappaLine(String);
public boolean equals(Object);
public int getArrowType();
public int getWindingRule();
public boolean startsNear(java.awt.geom.Point2D);
public String toAttributeString();
public String toFormattedString(String);
public String toString();
public boolean changeArrowType(int);
private void addArrow(java.awt.geom.GeneralPath, java.awt.geom.GeneralPath, GrappaPoint, GrappaPoint, double, double);
private void updateLine(String);
private void updateLine(GrappaPoint[], int);
public Object clone();
public final boolean contains(double, double);
public final boolean contains(double, double, double, double);
public final boolean contains(java.awt.geom.Point2D);
public final boolean contains(java.awt.geom.Rectangle2D);
public final java.awt.Rectangle getBounds();
public final java.awt.geom.Rectangle2D getBounds2D();
public final java.awt.geom.PathIterator getPathIterator();
public final java.awt.geom.PathIterator getPathIterator(java.awt.geom.AffineTransform);
public final java.awt.geom.PathIterator getPathIterator(java.awt.geom.AffineTransform, double);
public final boolean intersects(double, double, double, double);
public final boolean intersects(java.awt.geom.Rectangle2D);
}
GrappaPathIterator
package att.grappa;
public synchronized class GrappaPathIterator implements java.awt.geom.PathIterator {
GrappaNexus grappaNexus;
java.awt.geom.AffineTransform affine;
java.awt.geom.PathIterator shapeIterator;
java.awt.geom.PathIterator areaIterator;
double[] pts;
int type;
public void GrappaPathIterator(GrappaNexus);
public void GrappaPathIterator(GrappaNexus, java.awt.geom.AffineTransform);
public int currentSegment(double[]);
public int currentSegment(float[]);
public int getWindingRule();
public boolean isDone();
public void next();
}
GrappaShape
package att.grappa;
public synchronized class GrappaShape implements GrappaConstants, Cloneable, java.awt.Shape {
protected java.awt.geom.GeneralPath path;
private static final double RBCONST = 12.0;
private static final double RBCURVE = 0.5;
private static final double CIRCLE_XDIAG;
private static final double CIRCLE_YDIAG = 0.75;
public void GrappaShape(int, double, double, double, double, int, int, double, double, double, boolean, boolean, Object);
public Object clone();
public final boolean contains(double, double);
public final boolean contains(double, double, double, double);
public final boolean contains(java.awt.geom.Point2D);
public final boolean contains(java.awt.geom.Rectangle2D);
public final java.awt.Rectangle getBounds();
public final java.awt.geom.Rectangle2D getBounds2D();
public final java.awt.geom.PathIterator getPathIterator();
public final java.awt.geom.PathIterator getPathIterator(java.awt.geom.AffineTransform);
public final java.awt.geom.PathIterator getPathIterator(java.awt.geom.AffineTransform, double);
public final boolean intersects(double, double, double, double);
public final boolean intersects(java.awt.geom.Rectangle2D);
static void
}
GrappaSupport
package att.grappa;
public abstract synchronized class GrappaSupport implements GrappaConstants {
private static final short CN = 1;
private static final short WS = 2;
private static final short SP = 4;
private static final short PU = 8;
private static final short DG = 16;
private static final short OD = 32;
private static final short UC = 64;
private static final short HD = 128;
private static final short LC = 256;
private static final short[] ctype;
private static final short ALPHA = 320;
private static final short ALNUM = 336;
private static final short GRAPH = 344;
private static final short PRINT = 348;
private static final short ODIGIT = 32;
private static final short XDIGIT = 144;
private static final short LOWERTOUPPER = -32;
private static final short UPPERTOLOWER = 32;
public void GrappaSupport();
static boolean isalnum(int);
static boolean isalpha(int);
static boolean isascii(int);
static boolean iscntrl(int);
static boolean isdigit(int);
static boolean isgraph(int);
static boolean islower(int);
static boolean isoctal(int);
static boolean isprint(int);
static boolean ispunct(int);
static boolean isspace(int);
static boolean isupper(int);
static boolean isxdigit(int);
static int tolower(int);
static int toupper(int);
static String[] strsplit(String) throws IllegalArgumentException;
static float[] floatArrayForTuple(String) throws IllegalArgumentException, NumberFormatException;
static double[] arrayForTuple(String) throws IllegalArgumentException, NumberFormatException;
public static int xlateDirString(String);
public static String xlateDir(int);
public static int xlateFontStyleString(String);
public static String xlateFontStyle(int);
public static String canonize(String);
public static GrappaBox boxFromCorners(double, double, double, double);
public static GrappaBox boxFromCorners(GrappaBox, double, double, double, double);
public static Element findContainingElement(Subgraph, java.awt.geom.Point2D);
public static java.util.Vector findContainedElements(Subgraph, GrappaBox);
public static void setHighlight(Element, int, int);
public static boolean filterGraph(Graph, Object);
public static boolean filterGraph(Graph, Object, String);
public static boolean centerPanel(java.awt.geom.Point2D, GrappaPanel);
static void
}
GrappaSupportPrintf
package att.grappa;
public synchronized class GrappaSupportPrintf implements GrappaConstants {
public void GrappaSupportPrintf();
public static final String sprintf(Object[]);
}
PrintfParser
package att.grappa;
synchronized class PrintfParser implements GrappaConstants {
private boolean alternate;
private boolean rightpad;
private boolean sign;
private boolean space;
private boolean zeropad;
private boolean trim;
private int precision;
private int width;
private String plus;
private char padding;
private StringBuffer scratch;
void PrintfParser();
final int parse(char[]);
final int parse(char[], int);
final StringBuffer buildChar(StringBuffer, int);
final StringBuffer buildExp(StringBuffer, double, boolean);
final StringBuffer buildFlex(StringBuffer, double, boolean);
final StringBuffer buildPoint(StringBuffer, java.awt.geom.Point2D, boolean);
final StringBuffer buildSize(StringBuffer, java.awt.geom.Dimension2D, boolean);
final StringBuffer buildBox(StringBuffer, java.awt.geom.Rectangle2D, boolean, boolean);
final StringBuffer buildFloat(StringBuffer, double);
final StringBuffer buildHex(StringBuffer, int, boolean);
final StringBuffer buildInteger(StringBuffer, long);
final StringBuffer buildOctal(StringBuffer, int);
final StringBuffer buildString(StringBuffer, String);
private String doubleToString(double, String);
private StringBuffer strpad(StringBuffer, String, int, int, boolean);
}
GrappaSupportRects
package att.grappa;
public synchronized class GrappaSupportRects implements GrappaConstants {
static final double[] romanFontwidth;
static final double[] helveticaFontwidth;
static final double constantFontwidth = 0.6206;
static final int HASTEXT = 1;
static final int HASPORT = 2;
static final int HASTABLE = 4;
static final int INTEXT = 8;
static final int INPORT = 16;
static final char NBSP = 160;
private static char[] parseArray;
private static int arrayOffset;
private static int fields;
private static StringBuffer rbuf;
public void GrappaSupportRects();
protected static synchronized Object[] parseRecordInfo(Node);
private static boolean emitFields(TableField, Object[]);
private static TableField doParse(Node, boolean, boolean);
private static boolean isSpec(char);
static void
}
TableField
package att.grappa;
synchronized class TableField implements GrappaConstants {
private java.awt.Dimension size;
private java.awt.Rectangle bounds;
private java.awt.Rectangle textBounds;
private TableField[] subFields;
private int subFieldsUsed;
private boolean orientLR;
private String idTag;
private String text;
private TableField parent;
void TableField();
void setParent(TableField);
TableField getTopMost();
TableField getParent();
String getText();
String getIdentifier();
java.awt.Rectangle getBounds();
void setBounds(int, int, int, int);
void setBounds(java.awt.Rectangle);
java.awt.Dimension getSize();
void setSize(int, int);
void setSize(java.awt.Dimension);
boolean hasFields();
synchronized int subfields(int);
int fieldCount();
synchronized void addField(TableField);
TableField fieldAt(int);
boolean isLR();
void setLR(boolean);
String getId();
void setId(String);
java.awt.Dimension sizeFields();
private java.awt.Dimension sizeUpFields(TableField);
java.awt.Dimension resizeFields(java.awt.Dimension);
void resizeUpFields(TableField, java.awt.Dimension);
void positionFields(java.awt.Point);
private void posFields(TableField, java.awt.Point);
void setTextBounds(String, Node);
java.awt.Rectangle getTextBounds();
void debugID();
}
Lexer
package att.grappa;
public synchronized class Lexer {
private int next_char;
private int next_char2;
private int current_line;
private int current_position;
private static final int EOF_CHAR = -1;
private boolean haveId;
private int old_char;
private int old_position;
boolean retreated;
private int error_count;
private int warning_count;
private java.util.Hashtable keywords;
private java.util.Hashtable char_symbols;
private java.io.Reader inReader;
private java.io.PrintWriter errWriter;
private StringBuffer cmnstrbuf;
public void Lexer(java.io.Reader, java.io.PrintWriter) throws IllegalArgumentException;
public void init() throws java.io.IOException;
public void advance() throws java.io.IOException;
private void retreat();
private void emit_error(String);
public String getLocation();
private void emit_warn(String);
public static boolean id_char(int);
public static boolean id_char(char);
private int find_single_char(int);
private void swallow_comment() throws java.io.IOException;
private java_cup.runtime.Symbol do_quote_string() throws java.io.IOException;
private java_cup.runtime.Symbol do_id() throws java.io.IOException;
private java_cup.runtime.Symbol real_next_token() throws java.io.IOException;
public java_cup.runtime.Symbol next_token(int) throws java.io.IOException;
}
Parser
package att.grappa;
public synchronized class Parser extends java_cup.runtime.lr_parser {
protected static final short[][] _production_table;
protected static final short[][] _action_table;
protected static final short[][] _reduce_table;
protected CUP$Parser$actions action_obj;
private Graph theGraph;
private java.io.Reader inReader;
private java.io.PrintWriter errWriter;
private Lexer lexer;
private int debugLevel;
public void Parser();
public void Parser(java_cup.runtime.Scanner);
public short[][] production_table();
public short[][] action_table();
public short[][] reduce_table();
protected void init_actions();
public java_cup.runtime.Symbol do_action(int, java_cup.runtime.lr_parser, java.util.Stack, int) throws Exception;
public int start_state();
public int start_production();
public int EOF_sym();
public int error_sym();
public void user_init() throws Exception;
public java_cup.runtime.Symbol scan() throws Exception;
public void Parser(java.io.Reader, java.io.PrintWriter, Graph);
public void Parser(java.io.Reader, java.io.PrintWriter);
public void Parser(java.io.Reader);
public void Parser(java.io.InputStream, java.io.OutputStream, Graph);
public void Parser(java.io.InputStream, java.io.OutputStream);
public void Parser(java.io.InputStream);
public Lexer getLexer();
public java.io.PrintWriter getErrorWriter();
public int getDebugLevel();
public void report_error(String, Object) throws GraphParserException;
public void report_warning(String, Object);
public void debug_message(String);
public void debug_message(int, String);
public java_cup.runtime.Symbol debug_parse(int) throws Exception;
CUP$Parser$actions getActionObject();
public Graph getGraph();
static void
}
CUP$Parser$actions
package att.grappa;
synchronized class CUP$Parser$actions {
Subgraph rootSubgraph;
Subgraph lastSubgraph;
Graph graph;
Subgraph thisGraph;
Node thisNode;
Edge thisEdge;
Node fromNode;
Node toNode;
String portName;
String toPortName;
String fromPortName;
int thisAttrType;
int thisElemType;
boolean directed;
String graphType;
private int anon_id;
java.util.Vector attrs;
java.util.Vector nodes;
java.util.Vector edges;
private final Parser parser;
void appendAttr(String, String);
void noMacros();
void attrStmt(int, String);
void startGraph(String, boolean, boolean);
void openGraph();
void closeGraph();
void openSubg(String);
String anonStr();
void closeSubg();
void appendNode(String, String);
void nodeWrap();
void bufferEdges();
void edgeWrap();
void edgeRHS(Node, String, Object[], Attribute, Attribute);
void applyAttrs(Element, Attribute, Attribute);
void CUP$Parser$actions(Parser);
public final java_cup.runtime.Symbol CUP$Parser$do_action(int, java_cup.runtime.lr_parser, java.util.Stack, int) throws Exception;
}
Symbols
package att.grappa;
public synchronized class Symbols {
public static final int SUBGRAPH = 5;
public static final int DIGRAPH = 9;
public static final int RBR = 17;
public static final int EQUAL = 18;
public static final int D_EDGE_OP = 6;
public static final int SEMI = 12;
public static final int STRICTDIGRAPH = 11;
public static final int ATSIGN = 20;
public static final int COLON = 19;
public static final int ATOM = 21;
public static final int RCUR = 15;
public static final int STRICT = 8;
public static final int COMMA = 13;
public static final int LCUR = 14;
public static final int EOF = 0;
public static final int ND_EDGE_OP = 7;
public static final int EDGE = 4;
public static final int GRAPH = 2;
public static final int error = 1;
public static final int LBR = 16;
public static final int STRICTGRAPH = 10;
public static final int NODE = 3;
static final int graphType = 2;
static final int optAttr = 20;
static final int attrAssignment = 29;
static final int graph = 9;
static final int hdr = 10;
static final int graphAttrDefs = 25;
static final int edge_op = 31;
static final int optSeparator = 17;
static final int optSemi = 16;
static final int NT$2 = 34;
static final int NT$1 = 33;
static final int NT$0 = 32;
static final int optStmtList = 12;
static final int $START = 0;
static final int subgraph = 22;
static final int optGraphName = 6;
static final int body = 11;
static final int optSubgHdr = 5;
static final int attrList = 24;
static final int attrItem = 28;
static final int node = 23;
static final int rCompound = 3;
static final int attrStmt = 15;
static final int simple = 19;
static final int optAttrDefs = 26;
static final int optStrict = 1;
static final int attrMacro = 30;
static final int optMacroName = 7;
static final int attrDefs = 27;
static final int optPort = 8;
static final int compound = 18;
static final int nodeList = 21;
static final int stmt = 14;
static final int attrType = 4;
static final int stmtList = 13;
public void Symbols();
}
java_cup/runtime/Scanner.java
java_cup/runtime/Scanner.javapackage java_cup.runtime;
/**
* Defines the Scanner interface, which CUP uses in the default
* implementation of lr_parser.scan()
. Integration
* of scanners implementing Scanner
is facilitated.
*
* @version last updated 23-Jul-1999
* @author David MacMahon
*/
/* *************************************************
Interface Scanner
Declares the next_token() method that should be
implemented by scanners. This method is typically
called by lr_parser.scan().
***************************************************/
public interface Scanner {
public Symbol next_token() throws java.lang.Exception;
}
java_cup/runtime/Symbol.java
java_cup/runtime/Symbol.javapackage java_cup.runtime;
/**
* Defines the Symbol class, which is used to represent all terminals
* and nonterminals while parsing. The lexer should pass CUP Symbols
* and CUP returns a Symbol.
*
* @version last updated: 7/3/96
* @author Frank Flannery
*/
/* ****************************************************************
Class Symbol
what the parser expects to receive from the lexer.
the token is identified as follows:
sym: the symbol type
parse_state: the parse state.
value: is the lexical value of type Object
left : is the left position in the original input file
right: is the right position in the original input file
******************************************************************/
public class Symbol {
/*******************************
Constructor for l,r values
*******************************/
public Symbol(int id, int l, int r, Object o) {
this(id);
left = l;
right = r;
value = o;
}
/*******************************
Constructor for no l,r values
********************************/
public Symbol(int id, Object o) {
this(id);
left = -1;
right = -1;
value = o;
}
/*****************************
Constructor for no value
***************************/
public Symbol(int sym_num, int l, int r) {
sym = sym_num;
left = l;
right = r;
value = null;
}
/***********************************
Constructor for no value or l,r
***********************************/
public Symbol(int sym_num) {
this(sym_num, -1);
left = -1;
right = -1;
value = null;
}
/***********************************
Constructor to give a start state
***********************************/
public Symbol(int sym_num, int state)
{
sym = sym_num;
parse_state = state;
}
/*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
/** The symbol number of the terminal or non terminal being represented */
public int sym;
/*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
/** The parse state to be recorded on the parse stack with this symbol.
* This field is for the convenience of the parser and shouldn’t be
* modified except by the parser.
*/
public int parse_state;
/** This allows us to catch some errors caused by scanners recycling
* symbols. For the use of the parser only. [CSA, 23-Jul-1999] */
boolean used_by_parser = false;
/*******************************
The data passed to parser
*******************************/
public int left, right;
public Object value;
/*****************************
Printing this token out. (Override for pretty-print).
****************************/
public String toString() { return “#”+sym; }
}
java_cup/runtime/lr_parser.java
java_cup/runtime/lr_parser.java
package java_cup.runtime;
import java.util.Stack;
/** This class implements a skeleton table driven LR parser. In general,
* LR parsers are a form of bottom up shift-reduce parsers. Shift-reduce
* parsers act by shifting input onto a parse stack until the Symbols
* matching the right hand side of a production appear on the top of the
* stack. Once this occurs, a reduce is performed. This involves removing
* the Symbols corresponding to the right hand side of the production
* (the so called “handle”) and replacing them with the non-terminal from
* the left hand side of the production.
*
* To control the decision of whether to shift or reduce at any given point,
* the parser uses a state machine (the “viable prefix recognition machine”
* built by the parser generator). The current state of the machine is placed
* on top of the parse stack (stored as part of a Symbol object representing
* a terminal or non terminal). The parse action table is consulted
* (using the current state and the current lookahead Symbol as indexes) to
* determine whether to shift or to reduce. When the parser shifts, it
* changes to a new state by pushing a new Symbol (containing a new state)
* onto the stack. When the parser reduces, it pops the handle (right hand
* side of a production) off the stack. This leaves the parser in the state
* it was in before any of those Symbols were matched. Next the reduce-goto
* table is consulted (using the new state and current lookahead Symbol as
* indexes) to determine a new state to go to. The parser then shifts to
* this goto state by pushing the left hand side Symbol of the production
* (also containing the new state) onto the stack.
*
* This class actually provides four LR parsers. The methods parse() and
* debug_parse() provide two versions of the main parser (the only difference
* being that debug_parse() emits debugging trace messages as it parses).
* In addition to these main parsers, the error recovery mechanism uses two
* more. One of these is used to simulate “parsing ahead” in the input
* without carrying out actions (to verify that a potential error recovery
* has worked), and the other is used to parse through buffered “parse ahead”
* input in order to execute all actions and re-synchronize the actual parser
* configuration.
*
* This is an abstract class which is normally filled out by a subclass
* generated by the JavaCup parser generator. In addition to supplying
* the actual parse tables, generated code also supplies methods which
* invoke various pieces of user supplied code, provide access to certain
* special Symbols (e.g., EOF and error), etc. Specifically, the following
* abstract methods are normally supplied by generated code:
*
-
*
- short[][] production_table()
* - Provides a reference to the production table (indicating the index of
* the left hand side non terminal and the length of the right hand side
* for each production in the grammar).
* - short[][] action_table()
* - Provides a reference to the parse action table.
* - short[][] reduce_table()
* - Provides a reference to the reduce-goto table.
* - int start_state()
* - Indicates the index of the start state.
* - int start_production()
* - Indicates the index of the starting production.
* - int EOF_sym()
* - Indicates the index of the EOF Symbol.
* - int error_sym()
* - Indicates the index of the error Symbol.
* - Symbol do_action()
* - Executes a piece of user supplied action code. This always comes at
* the point of a reduce in the parse, so this code also allocates and
* fills in the left hand side non terminal Symbol object that is to be
* pushed onto the stack for the reduce.
* - void init_actions()
* - Code to initialize a special object that encapsulates user supplied
* actions (this object is used by do_action() to actually carry out the
* actions).
*
*
* In addition to these routines that must be supplied by the
* generated subclass there are also a series of routines that may
* be supplied. These include:
*
-
*
- Symbol scan()
* - Used to get the next input Symbol from the scanner.
* - Scanner getScanner()
* - Used to provide a scanner for the default implementation of
* scan().
* - int error_sync_size()
* - This determines how many Symbols past the point of an error
* must be parsed without error in order to consider a recovery to
* be valid. This defaults to 3. Values less than 2 are not
* recommended.
* - void report_error(String message, Object info)
* - This method is called to report an error. The default implementation
* simply prints a message to System.err and where the error occurred.
* This method is often replaced in order to provide a more sophisticated
* error reporting mechanism.
* - void report_fatal_error(String message, Object info)
* - This method is called when a fatal error that cannot be recovered from
* is encountered. In the default implementation, it calls
* report_error() to emit a message, then throws an exception.
* - void syntax_error(Symbol cur_token)
* - This method is called as soon as syntax error is detected (but
* before recovery is attempted). In the default implementation it
* invokes: report_error(“Syntax error”, null);
* - void unrecovered_syntax_error(Symbol cur_token)
* - This method is called if syntax error recovery fails. In the default
* implementation it invokes:
* report_fatal_error(“Couldn’t repair and continue parse”, null);
*
*
* @see java_cup.runtime.Symbol
* @see java_cup.runtime.Symbol
* @see java_cup.runtime.virtual_parse_stack
* @version last updated: 7/3/96
* @author Frank Flannery
*/
public abstract class lr_parser {
/*———————————————————–*/
/*— Constructor(s) —————————————-*/
/*———————————————————–*/
/** Simple constructor. */
public lr_parser()
{
/* nothing to do here */
}
/** Constructor that sets the default scanner. [CSA/davidm] */
public lr_parser(Scanner s) {
this(); /* in case default constructor someday does something */
setScanner(s);
}
/*———————————————————–*/
/*— (Access to) Static (Class) Variables ——————*/
/*———————————————————–*/
/** The default number of Symbols after an error we much match to consider
* it recovered from.
*/
protected final static int _error_sync_size = 3;
/*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
/** The number of Symbols after an error we much match to consider it
* recovered from.
*/
protected int error_sync_size() {return _error_sync_size; }
/*———————————————————–*/
/*— (Access to) Instance Variables ————————*/
/*———————————————————–*/
/** Table of production information (supplied by generated subclass).
* This table contains one entry per production and is indexed by
* the negative-encoded values (reduce actions) in the action_table.
* Each entry has two parts, the index of the non-terminal on the
* left hand side of the production, and the number of Symbols
* on the right hand side.
*/
public abstract short[][] production_table();
/*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
/** The action table (supplied by generated subclass). This table is
* indexed by state and terminal number indicating what action is to
* be taken when the parser is in the given state (i.e., the given state
* is on top of the stack) and the given terminal is next on the input.
* States are indexed using the first dimension, however, the entries for
* a given state are compacted and stored in adjacent index, value pairs
* which are searched for rather than accessed directly (see get_action()).
* The actions stored in the table will be either shifts, reduces, or
* errors. Shifts are encoded as positive values (one greater than the
* state shifted to). Reduces are encoded as negative values (one less
* than the production reduced by). Error entries are denoted by zero.
*
* @see java_cup.runtime.lr_parser#get_action
*/
public abstract short[][] action_table();
/*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
/** The reduce-goto table (supplied by generated subclass). This
* table is indexed by state and non-terminal number and contains
* state numbers. States are indexed using the first dimension, however,
* the entries for a given state are compacted and stored in adjacent
* index, value pairs which are searched for rather than accessed
* directly (see get_reduce()). When a reduce occurs, the handle
* (corresponding to the RHS of the matched production) is popped off
* the stack. The new top of stack indicates a state. This table is
* then indexed by that state and the LHS of the reducing production to
* indicate where to “shift” to.
*
* @see java_cup.runtime.lr_parser#get_reduce
*/
public abstract short[][] reduce_table();
/*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
/** The index of the start state (supplied by generated subclass). */
public abstract int start_state();
/*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
/** The index of the start production (supplied by generated subclass). */
public abstract int start_production();
/*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
/** The index of the end of file terminal Symbol (supplied by generated
* subclass).
*/
public abstract int EOF_sym();
/*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
/** The index of the special error Symbol (supplied by generated subclass). */
public abstract int error_sym();
/*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
/** Internal flag to indicate when parser should quit. */
protected boolean _done_parsing = false;
/*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
/** This method is called to indicate that the parser should quit. This is
* normally called by an accept action, but can be used to cancel parsing
* early in other circumstances if desired.
*/
public void done_parsing()
{
_done_parsing = true;
}
/*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
/* Global parse state shared by parse(), error recovery, and
* debugging routines */
/*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
/** Indication of the index for top of stack (for use by actions). */
protected int tos;
/*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
/** The current lookahead Symbol. */
protected Symbol cur_token;
/*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
/** The parse stack itself. */
protected Stack stack = new Stack();
/*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
/** Direct reference to the production table. */
protected short[][] production_tab;
/*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
/** Direct reference to the action table. */
protected short[][] action_tab;
/*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
/** Direct reference to the reduce-goto table. */
protected short[][] reduce_tab;
/*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
/** This is the scanner object used by the default implementation
* of scan() to get Symbols. To avoid name conflicts with existing
* code, this field is private. [CSA/davidm] */
private Scanner _scanner;
/**
* Simple accessor method to set the default scanner.
*/
public void setScanner(Scanner s) { _scanner = s; }
/**
* Simple accessor method to get the default scanner.
*/
public Scanner getScanner() { return _scanner; }
/*———————————————————–*/
/*— General Methods —————————————*/
/*———————————————————–*/
/** Perform a bit of user supplied action code (supplied by generated
* subclass). Actions are indexed by an internal action number assigned
* at parser generation time.
*
* @param act_num the internal index of the action to be performed.
* @param parser the parser object we are acting for.
* @param stack the parse stack of that object.
* @param top the index of the top element of the parse stack.
*/
public abstract Symbol do_action(
int act_num,
lr_parser parser,
Stack stack,
int top)
throws java.lang.Exception;
/*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
/** User code for initialization inside the parser. Typically this
* initializes the scanner. This is called before the parser requests
* the first Symbol. Here this is just a placeholder for subclasses that
* might need this and we perform no action. This method is normally
* overridden by the generated code using this contents of the “init with”
* clause as its body.
*/
public void user_init() throws java.lang.Exception { }
/*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
/** Initialize the action object. This is called before the parser does
* any parse actions. This is filled in by generated code to create
* an object that encapsulates all action code.
*/
protected abstract void init_actions() throws java.lang.Exception;
/*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
/** Get the next Symbol from the input (supplied by generated subclass).
* Once end of file has been reached, all subsequent calls to scan
* should return an EOF Symbol (which is Symbol number 0). By default
* this method returns getScanner().next_token(); this implementation
* can be overriden by the generated parser using the code declared in
* the “scan with” clause. Do not recycle objects; every call to
* scan() should return a fresh object.
*/
public Symbol scan() throws java.lang.Exception {
return getScanner().next_token();
}
/*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
/** Report a fatal error. This method takes a message string and an
* additional object (to be used by specializations implemented in
* subclasses). Here in the base class a very simple implementation
* is provided which reports the error then throws an exception.
*
* @param message an error message.
* @param info an extra object reserved for use by specialized subclasses.
*/
public void report_fatal_error(
String message,
Object info)
throws java.lang.Exception
{
/* stop parsing (not really necessary since we throw an exception, but) */
done_parsing();
/* use the normal error message reporting to put out the message */
report_error(message, info);
/* throw an exception */
throw new Exception(“Can’t recover from previous error(s)”);
}
/*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
/** Report a non fatal error (or warning). This method takes a message
* string and an additional object (to be used by specializations
* implemented in subclasses). Here in the base class a very simple
* implementation is provided which simply prints the message to
* System.err.
*
* @param message an error message.
* @param info an extra object reserved for use by specialized subclasses.
*/
public void report_error(String message, Object info)
{
System.err.print(message);
if (info instanceof Symbol)
if (((Symbol)info).left != -1)
System.err.println(” at character ” + ((Symbol)info).left +
” of input”);
else System.err.println(“”);
else System.err.println(“”);
}
/*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
/** This method is called when a syntax error has been detected and recovery
* is about to be invoked. Here in the base class we just emit a
* “Syntax error” error message.
*
* @param cur_token the current lookahead Symbol.
*/
public void syntax_error(Symbol cur_token)
{
report_error(“Syntax error”, cur_token);
}
/*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
/** This method is called if it is determined that syntax error recovery
* has been unsuccessful. Here in the base class we report a fatal error.
*
* @param cur_token the current lookahead Symbol.
*/
public void unrecovered_syntax_error(Symbol cur_token)
throws java.lang.Exception
{
report_fatal_error(“Couldn’t repair and continue parse”, cur_token);
}
/*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
/** Fetch an action from the action table. The table is broken up into
* rows, one per state (rows are indexed directly by state number).
* Within each row, a list of index, value pairs are given (as sequential
* entries in the table), and the list is terminated by a default entry
* (denoted with a Symbol index of -1). To find the proper entry in a row
* we do a linear or binary search (depending on the size of the row).
*
* @param state the state index of the action being accessed.
* @param sym the Symbol index of the action being accessed.
*/
protected final short get_action(int state, int sym)
{
short tag;
int first, last, probe;
short[] row = action_tab[state];
/* linear search if we are < 10 entries */
if (row.length < 20)
for (probe = 0; probe < row.length; probe++)
{
/* is this entry labeled with our Symbol or the default? */
tag = row[probe++];
if (tag == sym || tag == -1)
{
/* return the next entry */
return row[probe];
}
}
/* otherwise binary search */
else
{
first = 0;
last = (row.length-1)/2 - 1; /* leave out trailing default entry */
while (first <= last)
{
probe = (first+last)/2;
if (sym == row[probe*2])
return row[probe*2+1];
else if (sym > row[probe*2])
first = probe+1;
else
last = probe-1;
}
/* not found, use the default at the end */
return row[row.length-1];
}
/* shouldn’t happened, but if we run off the end we return the
default (error == 0) */
return 0;
}
/*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
/** Fetch a state from the reduce-goto table. The table is broken up into
* rows, one per state (rows are indexed directly by state number).
* Within each row, a list of index, value pairs are given (as sequential
* entries in the table), and the list is terminated by a default entry
* (denoted with a Symbol index of -1). To find the proper entry in a row
* we do a linear search.
*
* @param state the state index of the entry being accessed.
* @param sym the Symbol index of the entry being accessed.
*/
protected final short get_reduce(int state, int sym)
{
short tag;
short[] row = reduce_tab[state];
/* if we have a null row we go with the default */
if (row == null)
return -1;
for (int probe = 0; probe < row.length; probe++)
{
/* is this entry labeled with our Symbol or the default? */
tag = row[probe++];
if (tag == sym || tag == -1)
{
/* return the next entry */
return row[probe];
}
}
/* if we run off the end we return the default (error == -1) */
return -1;
}
/*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
/** This method provides the main parsing routine. It returns only when
* done_parsing() has been called (typically because the parser has
* accepted, or a fatal error has been reported). See the header
* documentation for the class regarding how shift/reduce parsers operate
* and how the various tables are used.
*/
public Symbol parse() throws java.lang.Exception
{
/* the current action code */
int act;
/* the Symbol/stack element returned by a reduce */
Symbol lhs_sym = null;
/* information about production being reduced with */
short handle_size, lhs_sym_num;
/* set up direct reference to tables to drive the parser */
production_tab = production_table();
action_tab = action_table();
reduce_tab = reduce_table();
/* initialize the action encapsulation object */
init_actions();
/* do user initialization */
user_init();
/* get the first token */
cur_token = scan();
/* push dummy Symbol with start state to get us underway */
stack.removeAllElements();
stack.push(new Symbol(0, start_state()));
tos = 0;
/* continue until we are told to stop */
for (_done_parsing = false; !_done_parsing; )
{
/* Check current token for freshness. */
if (cur_token.used_by_parser)
throw new Error("Symbol recycling detected (fix your scanner).");
/* current state is always on the top of the stack */
/* look up action out of the current state with the current input */
act = get_action(((Symbol)stack.peek()).parse_state, cur_token.sym);
/* decode the action -- > 0 encodes shift */
if (act > 0)
{
/* shift to the encoded state by pushing it on the stack */
cur_token.parse_state = act-1;
cur_token.used_by_parser = true;
stack.push(cur_token);
tos++;
/* advance to the next Symbol */
cur_token = scan();
}
/* if its less than zero, then it encodes a reduce action */
else if (act < 0)
{
/* perform the action for the reduce */
lhs_sym = do_action((-act)-1, this, stack, tos);
/* look up information about the production */
lhs_sym_num = production_tab[(-act)-1][0];
handle_size = production_tab[(-act)-1][1];
/* pop the handle off the stack */
for (int i = 0; i < handle_size; i++)
{
stack.pop();
tos--;
}
/* look up the state to go to from the one popped back to */
act = get_reduce(((Symbol)stack.peek()).parse_state, lhs_sym_num);
/* shift to that state */
lhs_sym.parse_state = act;
lhs_sym.used_by_parser = true;
stack.push(lhs_sym);
tos++;
}
/* finally if the entry is zero, we have an error */
else if (act == 0)
{
/* call user syntax error reporting routine */
syntax_error(cur_token);
/* try to error recover */
if (!error_recovery(false))
{
/* if that fails give up with a fatal syntax error */
unrecovered_syntax_error(cur_token);
/* just in case that wasn't fatal enough, end parse */
done_parsing();
} else {
lhs_sym = (Symbol)stack.peek();
}
}
}
return lhs_sym;
}
/*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
/** Write a debugging message to System.err for the debugging version
* of the parser.
*
* @param mess the text of the debugging message.
*/
public void debug_message(String mess)
{
System.err.println(mess);
}
/*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
/** Dump the parse stack for debugging purposes. */
public void dump_stack()
{
if (stack == null)
{
debug_message("# Stack dump requested, but stack is null");
return;
}
debug_message("============ Parse Stack Dump ============");
/* dump the stack */
for (int i=0; i
if ((i%3)==2 || (i==(stack.size()-1))) {
debug_message(sb.toString());
sb = new StringBuffer(” “);
}
}
}
/*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
/** Perform a parse with debugging output. This does exactly the
* same things as parse(), except that it calls debug_shift() and
* debug_reduce() when shift and reduce moves are taken by the parser
* and produces various other debugging messages.
*/
public Symbol debug_parse()
throws java.lang.Exception
{
/* the current action code */
int act;
/* the Symbol/stack element returned by a reduce */
Symbol lhs_sym = null;
/* information about production being reduced with */
short handle_size, lhs_sym_num;
/* set up direct reference to tables to drive the parser */
production_tab = production_table();
action_tab = action_table();
reduce_tab = reduce_table();
debug_message(“# Initializing parser”);
/* initialize the action encapsulation object */
init_actions();
/* do user initialization */
user_init();
/* the current Symbol */
cur_token = scan();
debug_message(“# Current Symbol is #” + cur_token.sym);
/* push dummy Symbol with start state to get us underway */
stack.removeAllElements();
stack.push(new Symbol(0, start_state()));
tos = 0;
/* continue until we are told to stop */
for (_done_parsing = false; !_done_parsing; )
{
/* Check current token for freshness. */
if (cur_token.used_by_parser)
throw new Error(“Symbol recycling detected (fix your scanner).”);
/* current state is always on the top of the stack */
//debug_stack();
/* look up action out of the current state with the current input */
act = get_action(((Symbol)stack.peek()).parse_state, cur_token.sym);
/* decode the action — > 0 encodes shift */
if (act > 0)
{
/* shift to the encoded state by pushing it on the stack */
cur_token.parse_state = act-1;
cur_token.used_by_parser = true;
debug_shift(cur_token);
stack.push(cur_token);
tos++;
/* advance to the next Symbol */
cur_token = scan();
debug_message(“# Current token is ” + cur_token);
}
/* if its less than zero, then it encodes a reduce action */
else if (act < 0)
{
/* perform the action for the reduce */
lhs_sym = do_action((-act)-1, this, stack, tos);
/* look up information about the production */
lhs_sym_num = production_tab[(-act)-1][0];
handle_size = production_tab[(-act)-1][1];
debug_reduce((-act)-1, lhs_sym_num, handle_size);
/* pop the handle off the stack */
for (int i = 0; i < handle_size; i++)
{
stack.pop();
tos--;
}
/* look up the state to go to from the one popped back to */
act = get_reduce(((Symbol)stack.peek()).parse_state, lhs_sym_num);
debug_message("# Reduce rule: top state " +
((Symbol)stack.peek()).parse_state +
", lhs sym " + lhs_sym_num + " -> state ” + act);
/* shift to that state */
lhs_sym.parse_state = act;
lhs_sym.used_by_parser = true;
stack.push(lhs_sym);
tos++;
debug_message(“# Goto state #” + act);
}
/* finally if the entry is zero, we have an error */
else if (act == 0)
{
/* call user syntax error reporting routine */
syntax_error(cur_token);
/* try to error recover */
if (!error_recovery(true))
{
/* if that fails give up with a fatal syntax error */
unrecovered_syntax_error(cur_token);
/* just in case that wasn’t fatal enough, end parse */
done_parsing();
} else {
lhs_sym = (Symbol)stack.peek();
}
}
}
return lhs_sym;
}
/*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
/* Error recovery code */
/*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
/** Attempt to recover from a syntax error. This returns false if recovery
* fails, true if it succeeds. Recovery happens in 4 steps. First we
* pop the parse stack down to a point at which we have a shift out
* of the top-most state on the error Symbol. This represents the
* initial error recovery configuration. If no such configuration is
* found, then we fail. Next a small number of “lookahead” or “parse
* ahead” Symbols are read into a buffer. The size of this buffer is
* determined by error_sync_size() and determines how many Symbols beyond
* the error must be matched to consider the recovery a success. Next,
* we begin to discard Symbols in attempt to get past the point of error
* to a point where we can continue parsing. After each Symbol, we attempt
* to “parse ahead” though the buffered lookahead Symbols. The “parse ahead”
* process simulates that actual parse, but does not modify the real
* parser’s configuration, nor execute any actions. If we can parse all
* the stored Symbols without error, then the recovery is considered a
* success. Once a successful recovery point is determined, we do an
* actual parse over the stored input — modifying the real parse
* configuration and executing all actions. Finally, we return the the
* normal parser to continue with the overall parse.
*
* @param debug should we produce debugging messages as we parse.
*/
protected boolean error_recovery(boolean debug)
throws java.lang.Exception
{
if (debug) debug_message(“# Attempting error recovery”);
/* first pop the stack back into a state that can shift on error and
do that shift (if that fails, we fail) */
if (!find_recovery_config(debug))
{
if (debug) debug_message(“# Error recovery fails”);
return false;
}
/* read ahead to create lookahead we can parse multiple times */
read_lookahead();
/* repeatedly try to parse forward until we make it the required dist */
for (;;)
{
/* try to parse forward, if it makes it, bail out of loop */
if (debug) debug_message(“# Trying to parse ahead”);
if (try_parse_ahead(debug))
{
break;
}
/* if we are now at EOF, we have failed */
if (lookahead[0].sym == EOF_sym())
{
if (debug) debug_message(“# Error recovery fails at EOF”);
return false;
}
/* otherwise, we consume another Symbol and try again */
if (debug)
debug_message(“# Consuming Symbol #” + cur_err_token().sym);
restart_lookahead();
}
/* we have consumed to a point where we can parse forward */
if (debug) debug_message(“# Parse-ahead ok, going back to normal parse”);
/* do the real parse (including actions) across the lookahead */
parse_lookahead(debug);
/* we have success */
return true;
}
/*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
/** Determine if we can shift under the special error Symbol out of the
* state currently on the top of the (real) parse stack.
*/
protected boolean shift_under_error()
{
/* is there a shift under error Symbol */
return get_action(((Symbol)stack.peek()).parse_state, error_sym()) > 0;
}
/*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
/** Put the (real) parse stack into error recovery configuration by
* popping the stack down to a state that can shift on the special
* error Symbol, then doing the shift. If no suitable state exists on
* the stack we return false
*
* @param debug should we produce debugging messages as we parse.
*/
protected boolean find_recovery_config(boolean debug)
{
Symbol error_token;
int act;
if (debug) debug_message(“# Finding recovery state on stack”);
/* Remember the right-position of the top symbol on the stack */
int right_pos = ((Symbol)stack.peek()).right;
int left_pos = ((Symbol)stack.peek()).left;
/* pop down until we can shift under error Symbol */
while (!shift_under_error())
{
/* pop the stack */
if (debug)
debug_message(“# Pop stack by one, state was # ” +
((Symbol)stack.peek()).parse_state);
left_pos = ((Symbol)stack.pop()).left;
tos–;
/* if we have hit bottom, we fail */
if (stack.empty())
{
if (debug) debug_message(“# No recovery state found on stack”);
return false;
}
}
/* state on top of the stack can shift under error, find the shift */
act = get_action(((Symbol)stack.peek()).parse_state, error_sym());
if (debug)
{
debug_message(“# Recover state found (#” +
((Symbol)stack.peek()).parse_state + “)”);
debug_message(“# Shifting on error to state #” + (act-1));
}
/* build and shift a special error Symbol */
error_token = new Symbol(error_sym(), left_pos, right_pos);
error_token.parse_state = act-1;
error_token.used_by_parser = true;
stack.push(error_token);
tos++;
return true;
}
/*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
/** Lookahead Symbols used for attempting error recovery “parse aheads”. */
protected Symbol lookahead[];
/** Position in lookahead input buffer used for “parse ahead”. */
protected int lookahead_pos;
/*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
/** Read from input to establish our buffer of “parse ahead” lookahead
* Symbols.
*/
protected void read_lookahead() throws java.lang.Exception
{
/* create the lookahead array */
lookahead = new Symbol[error_sync_size()];
/* fill in the array */
for (int i = 0; i < error_sync_size(); i++)
{
lookahead[i] = cur_token;
cur_token = scan();
}
/* start at the beginning */
lookahead_pos = 0;
}
/*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
/** Return the current lookahead in our error "parse ahead" buffer. */
protected Symbol cur_err_token() { return lookahead[lookahead_pos]; }
/*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
/** Advance to next "parse ahead" input Symbol. Return true if we have
* input to advance to, false otherwise.
*/
protected boolean advance_lookahead()
{
/* advance the input location */
lookahead_pos++;
/* return true if we didn't go off the end */
return lookahead_pos < error_sync_size();
}
/*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
/** Reset the parse ahead input to one Symbol past where we started error
* recovery (this consumes one new Symbol from the real input).
*/
protected void restart_lookahead() throws java.lang.Exception
{
/* move all the existing input over */
for (int i = 1; i < error_sync_size(); i++)
lookahead[i-1] = lookahead[i];
/* read a new Symbol into the last spot */
cur_token = scan();
lookahead[error_sync_size()-1] = cur_token;
/* reset our internal position marker */
lookahead_pos = 0;
}
/*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
/** Do a simulated parse forward (a "parse ahead") from the current
* stack configuration using stored lookahead input and a virtual parse
* stack. Return true if we make it all the way through the stored
* lookahead input without error. This basically simulates the action of
* parse() using only our saved "parse ahead" input, and not executing any
* actions.
*
* @param debug should we produce debugging messages as we parse.
*/
protected boolean try_parse_ahead(boolean debug)
throws java.lang.Exception
{
int act;
short lhs, rhs_size;
/* create a virtual stack from the real parse stack */
virtual_parse_stack vstack = new virtual_parse_stack(stack);
/* parse until we fail or get past the lookahead input */
for (;;)
{
/* look up the action from the current state (on top of stack) */
act = get_action(vstack.top(), cur_err_token().sym);
/* if its an error, we fail */
if (act == 0) return false;
/* > 0 encodes a shift */
if (act > 0)
{
/* push the new state on the stack */
vstack.push(act-1);
if (debug) debug_message(“# Parse-ahead shifts Symbol #” +
cur_err_token().sym + ” into state #” + (act-1));
/* advance simulated input, if we run off the end, we are done */
if (!advance_lookahead()) return true;
}
/* < 0 encodes a reduce */
else
{
/* if this is a reduce with the start production we are done */
if ((-act)-1 == start_production())
{
if (debug) debug_message("# Parse-ahead accepts");
return true;
}
/* get the lhs Symbol and the rhs size */
lhs = production_tab[(-act)-1][0];
rhs_size = production_tab[(-act)-1][1];
/* pop handle off the stack */
for (int i = 0; i < rhs_size; i++)
vstack.pop();
if (debug)
debug_message("# Parse-ahead reduces: handle size = " +
rhs_size + " lhs = #" + lhs + " from state #" + vstack.top());
/* look up goto and push it onto the stack */
vstack.push(get_reduce(vstack.top(), lhs));
if (debug)
debug_message("# Goto state #" + vstack.top());
}
}
}
/*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
/** Parse forward using stored lookahead Symbols. In this case we have
* already verified that parsing will make it through the stored lookahead
* Symbols and we are now getting back to the point at which we can hand
* control back to the normal parser. Consequently, this version of the
* parser performs all actions and modifies the real parse configuration.
* This returns once we have consumed all the stored input or we accept.
*
* @param debug should we produce debugging messages as we parse.
*/
protected void parse_lookahead(boolean debug)
throws java.lang.Exception
{
/* the current action code */
int act;
/* the Symbol/stack element returned by a reduce */
Symbol lhs_sym = null;
/* information about production being reduced with */
short handle_size, lhs_sym_num;
/* restart the saved input at the beginning */
lookahead_pos = 0;
if (debug)
{
debug_message("# Reparsing saved input with actions");
debug_message("# Current Symbol is #" + cur_err_token().sym);
debug_message("# Current state is #" +
((Symbol)stack.peek()).parse_state);
}
/* continue until we accept or have read all lookahead input */
while(!_done_parsing)
{
/* current state is always on the top of the stack */
/* look up action out of the current state with the current input */
act =
get_action(((Symbol)stack.peek()).parse_state, cur_err_token().sym);
/* decode the action -- > 0 encodes shift */
if (act > 0)
{
/* shift to the encoded state by pushing it on the stack */
cur_err_token().parse_state = act-1;
cur_err_token().used_by_parser = true;
if (debug) debug_shift(cur_err_token());
stack.push(cur_err_token());
tos++;
/* advance to the next Symbol, if there is none, we are done */
if (!advance_lookahead())
{
if (debug) debug_message(“# Completed reparse”);
/* scan next Symbol so we can continue parse */
// BUGFIX by Chris Harris
// correct a one-off error by commenting out
// this next line.
/*cur_token = scan();*/
/* go back to normal parser */
return;
}
if (debug)
debug_message(“# Current Symbol is #” + cur_err_token().sym);
}
/* if its less than zero, then it encodes a reduce action */
else if (act < 0)
{
/* perform the action for the reduce */
lhs_sym = do_action((-act)-1, this, stack, tos);
/* look up information about the production */
lhs_sym_num = production_tab[(-act)-1][0];
handle_size = production_tab[(-act)-1][1];
if (debug) debug_reduce((-act)-1, lhs_sym_num, handle_size);
/* pop the handle off the stack */
for (int i = 0; i < handle_size; i++)
{
stack.pop();
tos--;
}
/* look up the state to go to from the one popped back to */
act = get_reduce(((Symbol)stack.peek()).parse_state, lhs_sym_num);
/* shift to that state */
lhs_sym.parse_state = act;
lhs_sym.used_by_parser = true;
stack.push(lhs_sym);
tos++;
if (debug) debug_message("# Goto state #" + act);
}
/* finally if the entry is zero, we have an error
(shouldn't happen here, but...)*/
else if (act == 0)
{
report_fatal_error("Syntax error", lhs_sym);
return;
}
}
}
/*-----------------------------------------------------------*/
/** Utility function: unpacks parse tables from strings */
protected static short[][] unpackFromStrings(String[] sa)
{
// Concatanate initialization strings.
StringBuffer sb = new StringBuffer(sa[0]);
for (int i=1; i
/* get a copy of the first Symbol we have not transfered */
stack_sym = (Symbol)real_stack.elementAt(real_stack.size()-1-real_next);
/* record the transfer */
real_next++;
/* put the state number from the Symbol onto the virtual stack */
vstack.push(new Integer(stack_sym.parse_state));
}
/*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
/** Indicate whether the stack is empty. */
public boolean empty()
{
/* if vstack is empty then we were unable to transfer onto it and
the whole thing is empty. */
return vstack.empty();
}
/*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
/** Return value on the top of the stack (without popping it). */
public int top() throws java.lang.Exception
{
if (vstack.empty())
throw new Exception(
“Internal parser error: top() called on empty virtual stack”);
return ((Integer)vstack.peek()).intValue();
}
/*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
/** Pop the stack. */
public void pop() throws java.lang.Exception
{
if (vstack.empty())
throw new Exception(
“Internal parser error: pop from empty virtual stack”);
/* pop it */
vstack.pop();
/* if we are now empty transfer an element (if there is one) */
if (vstack.empty())
get_from_real();
}
/*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
/** Push a state number onto the stack. */
public void push(int state_num)
{
vstack.push(new Integer(state_num));
}
/*———————————————————–*/
}
Symbol
package java_cup.runtime;
public synchronized class Symbol {
public int sym;
public int parse_state;
boolean used_by_parser;
public int left;
public int right;
public Object value;
public void Symbol(int, int, int, Object);
public void Symbol(int, Object);
public void Symbol(int, int, int);
public void Symbol(int);
public void Symbol(int, int);
public String toString();
}
lr_parser
package java_cup.runtime;
public abstract synchronized class lr_parser {
protected static final int _error_sync_size = 3;
protected boolean _done_parsing;
protected int tos;
protected Symbol cur_token;
protected java.util.Stack stack;
protected short[][] production_tab;
protected short[][] action_tab;
protected short[][] reduce_tab;
private Scanner _scanner;
protected Symbol[] lookahead;
protected int lookahead_pos;
public void lr_parser();
public void lr_parser(Scanner);
protected int error_sync_size();
public abstract short[][] production_table();
public abstract short[][] action_table();
public abstract short[][] reduce_table();
public abstract int start_state();
public abstract int start_production();
public abstract int EOF_sym();
public abstract int error_sym();
public void done_parsing();
public void setScanner(Scanner);
public Scanner getScanner();
public abstract Symbol do_action(int, lr_parser, java.util.Stack, int) throws Exception;
public void user_init() throws Exception;
protected abstract void init_actions() throws Exception;
public Symbol scan() throws Exception;
public void report_fatal_error(String, Object) throws Exception;
public void report_error(String, Object);
public void syntax_error(Symbol);
public void unrecovered_syntax_error(Symbol) throws Exception;
protected final short get_action(int, int);
protected final short get_reduce(int, int);
public Symbol parse() throws Exception;
public void debug_message(String);
public void dump_stack();
public void debug_reduce(int, int, int);
public void debug_shift(Symbol);
public void debug_stack();
public Symbol debug_parse() throws Exception;
protected boolean error_recovery(boolean) throws Exception;
protected boolean shift_under_error();
protected boolean find_recovery_config(boolean);
protected void read_lookahead() throws Exception;
protected Symbol cur_err_token();
protected boolean advance_lookahead();
protected void restart_lookahead() throws Exception;
protected boolean try_parse_ahead(boolean) throws Exception;
protected void parse_lookahead(boolean) throws Exception;
protected static short[][] unpackFromStrings(String[]);
}
Scanner
package java_cup.runtime;
public abstract interface Scanner {
public abstract Symbol next_token() throws Exception;
}
virtual_parse_stack
package java_cup.runtime;
public synchronized class virtual_parse_stack {
protected java.util.Stack real_stack;
protected int real_next;
protected java.util.Stack vstack;
public void virtual_parse_stack(java.util.Stack) throws Exception;
protected void get_from_real();
public boolean empty();
public int top() throws Exception;
public void pop() throws Exception;
public void push(int);
}