package graph;
import java.awt.*;
import java.util.*;
import java.lang.*;
import java.io.StreamTokenizer;
import java.io.InputStream;
import java.io.IOException;
import java.net.URL;
import java.applet.Applet;
/*
**************************************************************************
**
** Class BuildGraph
**
**************************************************************************
** Copyright (C) 1996 Leigh Brookshaw
**
** This program is free software; you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation; either version 2 of the License, or
** (at your option) any later version.
**
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with this program; if not, write to the Free Software
** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
**************************************************************************
**
** This class will parse a description file and build the
** plot based on the instructions in the file
**
*************************************************************************/
/**
* This class will parse a description file and build a
* plot based on the instructions in the file.
* The build Graph class, with attached Axes and DataSets can be accessed
* though methods in the class
*
* @version $Revision: 1.14 $, $Date: 1996/09/06 00:08:49 $
* @author Leigh Brookshaw
*/
public class BuildGraph extends ScanWord {
/*
**********************
** Constants
*********************/
/*
** Specifiy the integer values associated with keywords. Every integer
** in this list is associated with keyword used in the input file
*/
static final int BEGIN = 256;
static final int GRAPH2D = 257;
static final int MARKER = 258;
static final int AXIS = 259;
static final int URL = 260;
static final int DATA = 261;
static final int SIZE = 262;
static final int COLOR = 263;
static final int NAME = 264;
static final int TITLE = 265;
static final int LABEL = 266;
static final int FONT = 267;
static final int STYLE = 268;
static final int BOTTOM = 269;
static final int TOP = 270;
static final int LEFT = 271;
static final int RIGHT = 272;
static final int END = 273;
static final int G2DINT = 274;
static final int OFF = 275;
static final int ON = 276;
static final int ATTACH = 277;
static final int PLAIN = 278;
static final int BOLD = 279;
static final int ITALIC = 280;
static final int DEBUG = 281;
static final int GRID = 282;
static final int ZERO = 283;
static final int CONTOUR = 284;
static final int LLEVELS = 285;
static final int NUMBER = 286;
static final int CDATA = 287;
static final int FUNCTION = 288;
static final int XRANGE = 289;
static final int YRANGE = 290;
static final int BACKGROUND = 291;
static final int LOGCONTOURS = 292;
static final int CLABELS = 293;
static final int SQUARE = 294;
/*
** Specify Internal interger values. These constants are associated
** with objects nolonger in the context of the input file. But have
** been constructed by the program from a number of keyword commands.
*/
static final int MARKER_STYLE = 512;
static final int MARKER_COLOR = 513;
static final int MARKER_SIZE = 514;
static final int LABEL_COLOR = 515;
static final int LABEL_FONT = 517;
static final int GRID_COLOR = 520;
static final int GRID_OFF = 521;
static final int ZERO_COLOR = 522;
static final int ZERO_OFF = 523;
static final int MARKER_URL = 524;
static final int GRID_ON = 525;
static final int ZERO_ON = 526;
static final int XMIN = 527;
static final int XMAX = 528;
static final int YMIN = 529;
static final int YMAX = 530;
static final int XNUMBER = 531;
static final int YNUMBER = 532;
static final int LABEL_OFF = 533;
/**
* The BUILD stack. Everything pushed on this stack has to be
* built from other objects. An example would be a Font, which
* is constructed from Logical name, style and size.
*/
protected Stack build = new Stack();
/**
* The Object stack. All input tokens get pushed onto and
* popped off this stack.
*/
protected Stack object = new Stack();
/**
* The class vector. This contains final class objects that cannot be
* deleted. That is
* we don't want these classes unnattached and collected into the garbage.
* The obvious classes here are the main Graph2D class, the Axes of the plot
* DataSets etc.
*/
protected Vector built = new Vector();
/**
* The constructed Graph Object
*/
protected Object graph = null;
/**
* The TextLine containing the title
*/
protected TextLine graphtitle = null;
/**
* The Calling Applet
*/
protected Applet applet;
/**
* Debug. If true output copious debug messages. Though unless you know
* what is going on with the code most messages will probably be
* meaningless
*/
protected boolean debug = false;
/*
** This vector contains all the datasets as they are built.
** the data sets in this lists are then searched so that they can
** be attached to axis.
*/
private Vector datasets = new Vector();
/*
*********************
** Public Variables
********************/
/**
* Current line being parsed
*/
public int lineno = 1;
/**
* The current brace level. At the end of the input if all
* braces are matched the level should be back to zero.
*/
public int level = 0;
/*
*********************
** Constructors
*******************/
/**
* Instantiate the class
* @param in The inputstream to be read
* @param ap the driving applet.
*/
public BuildGraph( InputStream in, Applet ap ) {
super(in);
applet = ap;
/*
** Specifiy The Key Words and associate them with the integer Values
*/
addKeyWord("{", BEGIN);
addKeyWord("}", END);
addKeyWord("graph2d", GRAPH2D);
addKeyWord("g2dint", G2DINT);
addKeyWord("marker", MARKER);
addKeyWord("axis", AXIS);
addKeyWord("url", URL);
addKeyWord("data", DATA);
addKeyWord("size", SIZE);
addKeyWord("color", COLOR);
addKeyWord("name", NAME);
addKeyWord("title", TITLE);
addKeyWord("label", LABEL);
addKeyWord("font", FONT);
addKeyWord("style", STYLE);
addKeyWord("bottom", BOTTOM);
addKeyWord("top", TOP);
addKeyWord("left", LEFT);
addKeyWord("right", RIGHT);
addKeyWord("on", ON);
addKeyWord("off", OFF);
addKeyWord("attach", ATTACH);
addKeyWord("plain", PLAIN);
addKeyWord("bold", BOLD);
addKeyWord("italic", ITALIC);
addKeyWord("debug", DEBUG);
addKeyWord("grid", GRID);
addKeyWord("zero", ZERO);
addKeyWord("contour", CONTOUR);
addKeyWord("number", NUMBER);
addKeyWord("cdata", CDATA);
addKeyWord("function", FUNCTION);
addKeyWord("xrange", XRANGE);
addKeyWord("yrange", YRANGE);
addKeyWord("background", BACKGROUND);
addKeyWord("llevels", LLEVELS);
addKeyWord("square", SQUARE);
addKeyWord("log", LOGCONTOURS);
}
/********************
**
** Public Methods
**
********************/
/**
* Get the Graph object that has been built!
*/
public Object getGraph() {
return graph;
}
/**
* Get the title of the Graph
*/
public TextLine getGraphTitle() {
return graphtitle;
}
/**
* Get a vector of all the built Classes.
* Ie the DataSets, Axis, Graph etc.
* This can be used by an applet to override anything specified in the
* input file
*/
public Vector getBuilt() { return built; }
/**
* This is THE method that parses the input file and constructs the plot.
*/
public void parse() {
int token;
Object o;
NamedObject nobj;
boolean cont = true;
while( cont ) {
/*
** Grab a word from the stream and Do something with it!
*/
token = nextWord();
debugMessage("Main",token);
switch (token) {
/*
** Turn on the debug messages.
*/
case DEBUG:
debug = !debug;
break;
/*
** Instantiate the Graph class and push it onto
** the object stack!
*/
case CONTOUR:
if(graph != null) {
errorAtLine("Graph already defined.");
return;
}
graph = new Contour();
nobj = new NamedObject(graph, CONTOUR);
object.push(nobj);
break;
case G2DINT:
if(graph != null) {
errorAtLine("Graph already defined.");
return;
}
graph = new G2Dint();
nobj = new NamedObject(graph, G2DINT);
object.push(nobj);
break;
case GRAPH2D:
if(graph != null) {
errorAtLine("Graph already defined.");
return;
}
graph = new Graph2D();
nobj = new NamedObject(graph, GRAPH2D);
object.push(nobj);
break;
/*
** End of the file. Exit the loop
*/
case TT_EOF:
cont = false;
break;
/*
** End of Line - Increment the line counter
*/
case TT_EOL:
lineno++;
if( lineno == (lineno/10)*10 ) {
applet.showStatus("Reading input: Line "+lineno);
}
break;
/*
** LEFT, RIGHT, BOTTOM and TOP perform different tasks based on Context.
** Inside an AXIS group they position the axis and are standalone keywords
** Inside a GRAPH context they are followed by an integer and are the
** border widths in pixels.
*/
case LEFT: case RIGHT: case TOP: case BOTTOM:
if( isContext(AXIS) ) {
nobj = new NamedObject(token);
} else {
int toke = nextWord();
if( toke == TT_NUMBER ) {
nobj = new NamedObject(
new Integer((int)(nval+0.01)), token);
} else {
errorAtLine(
"In this context LEFT, RIGHT, TOP or BOTTOM should be followed an integer");
return;
}
}
object.push(nobj);
break;
/*
** Build a URL object and push it onto the object stack
** The URL keyword MUST be followed by a string
*/
case URL:
token = nextWord();
if( token == STRING ) {
try {
URL url = new URL(applet.getDocumentBase(),sval);
nobj = new NamedObject(url,URL);
} catch(Exception e) {
errorAtLine("Failed to build URL!");
return;
}
} else {
errorAtLine("URL should be followed by a string");
return;
}
object.push(nobj);
break;
/*
** The ATTACH keyword is followed by the name of the
** DataSet to be attached. Attach only appears
** inside an AXIS group.
*/
case ATTACH:
if( !isContext(AXIS) ) {
errorAtLine("ATTACH should only appear in AXIS context");
return;
}
token = nextWord();
if( token == STRING ) {
nobj = new NamedObject(sval,ATTACH);
} else {
errorAtLine("ATTACH should be followed by a string");
return;
}
object.push(nobj);
break;
/*
** Marker style, or font style depending on context
*/
case STYLE:
if( !isContext(MARKER) && !isContext(FONT)) {
errorAtLine(
"STYLE should only appear in MARKER or FONT context");
return;
}
token = nextWord();
if( token == PLAIN ) {
nobj = new NamedObject(PLAIN);
} else
if( token == BOLD ) {
nobj = new NamedObject(BOLD);
} else
if( token == ITALIC ) {
nobj = new NamedObject(PLAIN);
} else
if( token == TT_NUMBER ) {
nobj = new NamedObject(new Integer((int)(nval+0.01)), STYLE);
} else {
errorAtLine(
"STYLE should be followed an integer or Keyword");
return;
}
object.push(nobj);
break;
/*
** Size of font or marker. Size should be followed by an integer
*/
case SIZE:
if( !isContext(MARKER) && !isContext(FONT)) {
errorAtLine(
"SIZE should only appear in MARKER or FONT context");
return;
}
token = nextWord();
if( token == TT_NUMBER ) {
nobj = new NamedObject(new Integer((int)(nval+0.01)), SIZE);
} else {
errorAtLine("SIZE should be followed by an integer");
return;
}
object.push(nobj);
break;
/*
** Which contour levels are to get labels.
*/
case LLEVELS:
if( !isContext(CONTOUR)) {
errorAtLine(
"LLEVELS should only appear in CONTOUR context");
return;
}
token = nextWord();
if( token == TT_NUMBER ) {
nobj = new NamedObject(new Integer((int)(nval+0.01)), LLEVELS);
} else {
errorAtLine("LLEVELS should be followed by an integer");
return;
}
object.push(nobj);
break;
/*
** Parse a color. Color should be followed by 3 integers in
** the range 0-255
*/
case COLOR: case BACKGROUND:
int i;
int rgb[]={-1,-1,-1};
for(i=0; i<3; i++) {
int t = nextWord();
if(t != TT_NUMBER || nval <0 || nval > 255) {
errorAtLine("Incorrect Color definition");
return;
}
rgb[i] = (int)(nval+0.001);
}
if(token == COLOR) {
nobj = new NamedObject(new Color(rgb[0], rgb[1], rgb[2]), COLOR);
object.push(nobj);
} else {
if( isContext(DATA) || isContext(CDATA) ) {
((Graph2D)graph).setDataBackground(
new Color(rgb[0], rgb[1], rgb[2]) );
} else {
((Graph2D)graph).setGraphBackground(
new Color(rgb[0], rgb[1], rgb[2]) );
}
}
break;
/*
** Name the current context or the string to be used as a label
** or title. Name should be followed by a string
*/
case NAME:
token = nextWord();
if( token == STRING ) {
nobj = new NamedObject(sval,NAME);
} else {
errorAtLine("NAME should be followed by a string");
return;
}
object.push(nobj);
break;
case FUNCTION:
token = nextWord();
if( token == STRING ) {
nobj = new NamedObject(sval,FUNCTION);
} else {
errorAtLine("FUNCTION should be followed by a string");
return;
}
object.push(nobj);
break;
case NUMBER:
token = nextWord();
if( token == TT_NUMBER ) {
nobj = new NamedObject(
new Integer((int)(nval+0.01)), NUMBER);
} else {
errorAtLine("NUMBER should be followed by an integer");
return;
}
object.push(nobj);
break;
case XRANGE: case YRANGE:
boolean error = false;
double min = 0.0;
double max = 0.0;
int num = 0;
int t = nextWord();
if( t == TT_NUMBER ) {
num = (int)(nval+0.001);
t = nextWord();
if( t == TT_NUMBER ) {
min = nval;
t = nextWord();
if( t == TT_NUMBER ) {
max = nval;
} else {
error = true;
}
} else {
error = true;
}
} else {
error = true;
}
if(error) {
errorAtLine(
"Range limits must be followed by 3 numbers");
return;
}
if(min == max) {
errorAtLine(
"Range limits must not be the same");
return;
}
if(num <= 1) {
errorAtLine(
"Number of points must be greater than 1");
return;
}
if(min > max ) {
double tmp = max;
max = min;
min = tmp;
}
if(token == XRANGE) {
nobj = new NamedObject(new Integer(num),XNUMBER);
object.push(nobj);
nobj = new NamedObject(new Double(min),XMIN);
object.push(nobj);
nobj = new NamedObject(new Double(max),XMAX);
object.push(nobj);
} else {
nobj = new NamedObject(new Integer(num),YNUMBER);
object.push(nobj);
nobj = new NamedObject(new Double(min),YMIN);
object.push(nobj);
nobj = new NamedObject(new Double(max),YMAX);
object.push(nobj);
}
break;
/*
** unknown keyword!
*/
case UNKNOWN:
errorAtLine("Unknown keyword!!");
break;
/*
** begin a new group or context. The object to be built
** should be the last thing pushed onto the object stack.
** Move it to the build stack and push BEGIN onto the object
** stack to act as a delimiter on the stack
*/
case BEGIN:
level++;
build.push(object.pop());
object.push(new NamedObject(BEGIN));
break;
/*
** End of a group or context. Everything on the object stack
** down to the BEGIN object relate to the current build object
** Build the object and push this built object onto the
** object stack.
*/
case END:
level--;
build((NamedObject)(build.pop()));
break;
/*
** Whatever it is push it onto the object stack.
*/
default:
object.push(new NamedObject(token));
break;
}
}
/*
** Finished - lets see if anything major was not defined
*/
closeStream();
if(graph == null) {
System.out.println("Graph never defined! Cannot build graph!");
return;
}
if(level != 0 ) {
System.out.println("Mismatched Braces!! Will try and build graph.");
}
/*
** Errors could have occured - but lets try and repaint and keep going
*/
if( graph instanceof Graph2D ) {
((Graph2D)graph).repaint();
} else
if( graph instanceof G2Dint ) {
((G2Dint)graph).repaint();
} else
if( graph instanceof Contour ) {
((Contour)graph).repaint();
} else {
System.out.println("Unknown graph type - totally confused!");
}
}
/*
*********************
**
** Protected Methods
**
*********************/
/**
* Check if the object is on the "to be built" stack. This way context can be
* checked so potential errors flagged.
* @param token is this the object we are currently building?
* @return true if the token matches current object being built
*/
protected boolean isContext(int token) {
int i;
for(i=0; itrue if the build was successful.
*/
protected boolean build(NamedObject nobj) {
switch(nobj.id) {
case FONT: return buildFont();
case MARKER: return buildMarker();
case TITLE: return buildTitle();
case LABEL: return buildLabel();
case DATA: case CDATA: return buildData(nobj.id);
case AXIS: return buildAxis();
case GRID: return buildGrid();
case ZERO: return buildZero();
case G2DINT: case GRAPH2D: case CONTOUR:
return buildGraph(nobj.id);
default:
errorAtLine("Incorrect keyword followed by braces");
return false;
}
}
/**
* Pop things off the object stack and build the graph
* @param type Type of graph to build, Graph2D, G2Dint, Contour.
* @return true if the build was successful
*/
protected boolean buildGraph(int type) {
NamedObject nobj;
Axis axis;
String dname;
if(type==CONTOUR) dname = "Contour";
else
if(type==G2DINT) dname = "G2Dint";
else
dname = "Graph";
while( true ) {
nobj = (NamedObject)(object.pop());
debugMessage(dname,nobj.id);
switch (nobj.id) {
case AXIS:
axis = (Axis)(nobj.getObject());
if(type == GRAPH2D) {
((Graph2D)graph).attachAxis(axis);
} else {
((G2Dint)graph).attachAxis(axis);
}
break;
case DATA:
((Graph2D)graph).attachDataSet(
(DataSet)(nobj.getObject()));
break;
case ATTACH:
axis = (Axis)(nobj.getObject());
String name = nobj.getName();
boolean attach = false;
for(int i=0; itrue if the build was successful
*/
protected boolean buildContour(NamedObject nobj) {
switch (nobj.id) {
case NUMBER:
((Contour)graph).setNLevels(
((Integer)(nobj.getObject())).intValue() );
break;
case LLEVELS:
((Contour)graph).setLabelLevels(
((Integer)(nobj.getObject())).intValue() );
break;
case COLOR:
((Contour)graph).setContourColor(
(Color)(nobj.getObject()));
break;
case LOGCONTOURS:
((Contour)graph).logLevels = true;
break;
default:
return false;
}
return true;
}
/**
* @return true if the build was successful
*/
protected boolean buildFont() {
String name = "TimesRoman";
int style = Font.PLAIN;
int size = 20;
NamedObject nobj;
Font f;
while( true ) {
nobj = (NamedObject)(object.pop());
debugMessage("Font",nobj.id);
switch (nobj.id) {
case NAME:
name = (String)(nobj.getObject());
break;
case SIZE:
size = ((Integer)(nobj.getObject())).intValue();
break;
case PLAIN:
style += Font.PLAIN;
break;
case BOLD:
style += Font.BOLD;
break;
case ITALIC:
style += Font.ITALIC;
break;
case BEGIN:
try {
f = new Font(name,style,size);
nobj = new NamedObject(f,FONT);
object.push(nobj);
applet.showStatus("BuildGraph: Built Font!");
return true;
} catch(Exception e) {
errorAtLine("Ill formed font specification");
return false;
}
default:
errorAtLine("Incorrect keyword in Font specification");
return false;
}
}
}
/**
* @return true if the build was successful
*/
protected boolean buildTitle() {
NamedObject nobj;
TextLine title = new RTextLine();
while( true ) {
nobj = (NamedObject)(object.pop());
debugMessage("Title",nobj.id);
switch (nobj.id) {
case NAME:
title.setText((String)(nobj.getObject()));
break;
case FONT:
title.setFont((Font)(nobj.getObject()));
break;
case COLOR:
title.setColor((Color)(nobj.getObject()));
break;
case BEGIN:
nobj = new NamedObject(title,TITLE);
object.push(nobj);
applet.showStatus("BuildGraph: Built Title!");
return true;
default:
errorAtLine("Incorrect keyword in Title specification");
return false;
}
}
}
/**
* @return true if the build was successful
*/
protected boolean buildLabel() {
NamedObject nobj;
NamedObject color = null;
NamedObject font = null;
while( true ) {
nobj = (NamedObject)(object.pop());
debugMessage("Label",nobj.id);
switch (nobj.id) {
case FONT:
font = nobj;
font.setId(LABEL_FONT);
break;
case COLOR:
color = nobj;
color.setId(LABEL_COLOR);
break;
case BEGIN:
if(color != null) object.push(color);
if(font != null) object.push(font);
applet.showStatus("BuildGraph: Built Axis Label!");
return true;
default:
errorAtLine("Incorrect keyword in Label specification");
return false;
}
}
}
/*
* @return true if the build was successful
*/
protected boolean buildMarker() {
NamedObject nobj;
Markers m = null;
NamedObject size = null;
NamedObject color = null;
NamedObject style = null;
while( true ) {
nobj = (NamedObject)(object.pop());
debugMessage("Marker",nobj.id);
switch (nobj.id) {
case SIZE:
size = nobj;
size.setId(MARKER_SIZE);
break;
case COLOR:
color = nobj;
color.setId(MARKER_COLOR);
break;
case STYLE:
style = nobj;
if( style.getObject() instanceof Integer) {
style.setId(MARKER_STYLE);
} else {
errorAtLine("Style should be an Integer in MARKER");
return false;
}
break;
case URL:
try {
m = new Markers( (URL)nobj.getObject() );
} catch(Exception e) {
errorAtLine("Failed to load markers: "+
e.getMessage());
}
break;
case BEGIN:
if(m != null) {
nobj = new NamedObject(m,MARKER);
object.push(nobj);
built.addElement(m);
applet.showStatus(
"BuildGraph: Loaded Marker file!");
return true;
} else {
if(color != null) object.push(color);
if(size != null) object.push(size);
if(style != null) object.push(style);
applet.showStatus("BuildGraph: Built Marker!");
return true;
}
default:
errorAtLine("Incorrect keyword in MARKER specification");
return false;
}
}
}
/**
* @return true if the build was successful
*/
protected boolean buildData(int type) {
NamedObject nobj;
DataSet data = new DataSet();
NamedObject ndata = new NamedObject(data,DATA);
ParseFunction parsef = null;
LoadData load = null;
double xmin = 0.0;
double xmax = 0.0;
double ymin = 0.0;
double ymax = 0.0;
int nx = 0;
int ny = 0;
if(type == CDATA && !(graph instanceof Contour)) {
errorAtLine("CDATA can only be used in CONTOUR!");
}
while( true ) {
nobj = (NamedObject)(object.pop());
debugMessage("Data",nobj.id);
switch (nobj.id) {
case NAME:
ndata.setName((String)(nobj.getObject()));
break;
case MARKER_STYLE:
data.marker = ((Integer)(nobj.getObject())).intValue();
break;
case MARKER_SIZE:
data.markerscale = (double)(((Integer)(nobj.getObject())).intValue());
break;
case MARKER_COLOR:
data.markercolor = (Color)(nobj.getObject());
break;
case OFF:
data.linestyle = 0;
break;
case ON:
data.linestyle = 1;
break;
case COLOR:
if(type == CDATA) {
((Contour)graph).setContourColor(
(Color)(nobj.getObject()));
} else {
data.linecolor = (Color)(nobj.getObject());
}
break;
case URL:
load = new LoadData(data);
load.loadDataSet( (URL)(nobj.getObject()), graph);
break;
case FUNCTION:
parsef = new ParseFunction((String)(nobj.getObject()));
if(!parsef.parse()) {
errorAtLine("Error in function definition!");
return false;
}
break;
case XNUMBER:
nx = ((Integer)(nobj.getObject())).intValue();
break;
case XMIN:
xmin = ((Double)(nobj.getObject())).doubleValue();
break;
case XMAX:
xmax = ((Double)(nobj.getObject())).doubleValue();
break;
case YNUMBER:
ny = ((Integer)(nobj.getObject())).intValue();
break;
case YMIN:
ymin = ((Double)(nobj.getObject())).doubleValue();
break;
case YMAX:
ymax = ((Double)(nobj.getObject())).doubleValue();
break;
case BEGIN:
if( parsef != null && type == CDATA ) {
if( !(graph instanceof Contour) ) {
errorAtLine("CDATA should only be used for Contours!");
return false;
}
double array[] = arrayFromFunction(parsef,nx,xmin,xmax,
ny,ymin,ymax);
if(array == null) {
errorAtLine("Unable to build Data from Function");
return false;
}
((Contour)graph).setRange(xmin,xmax,ymin,ymax);
((Contour)graph).setGrid(array,nx,ny);
return true;
} else
if( parsef != null ) {
double array[] = arrayFromFunction(parsef,nx,xmin,xmax);
if(array == null) {
errorAtLine("Unable to build Data from Function");
return false;
}
try {
data.append(array,nx);
object.push(ndata);
datasets.addElement(ndata);
built.addElement(data);
return true;
} catch(Exception e) {
return false;
}
} else
if( load == null ) {
errorAtLine("No URL has been defined for Data!");
return false;
}
object.push(ndata);
built.addElement(data);
built.addElement(load);
datasets.addElement(ndata);
applet.showStatus("BuildGraph: Loading Data!");
return true;
default:
errorAtLine("Incorrect keyword in Data specification");
return false;
}
}
}
protected double[] arrayFromFunction(ParseFunction f, int nx,
double xmin, double xmax) {
double x;
double y;
double array[] = new double[2*nx];
double xinc = (xmax-xmin)/(nx-1);
int count = 0;
for(int i=0; itrue if the build was successful
*/
protected boolean buildAxis() {
Stack attach = new Stack();
NamedObject nobj;
Axis axis = new Axis();
NamedObject naxis = new NamedObject(axis,AXIS);
int angle = 0;
while( true ) {
nobj = (NamedObject)(object.pop());
debugMessage("Axis",nobj.id);
switch (nobj.id) {
case NAME:
naxis.setName((String)(nobj.getObject()));
break;
case TITLE:
axis.title = (RTextLine)(nobj.getObject());
break;
case LABEL_FONT:
axis.label.setFont((Font)(nobj.getObject()));
break;
case LABEL_COLOR:
axis.label.setColor((Color)(nobj.getObject()));
break;
case BOTTOM:
axis.setPosition(Axis.BOTTOM);
break;
case TOP:
axis.setPosition(Axis.TOP);
break;
case LEFT:
axis.setPosition(Axis.LEFT);
angle = 90;
break;
case RIGHT:
axis.setPosition(Axis.RIGHT);
angle = -90;
break;
case ATTACH:
attach.push(new NamedObject(axis,
(String)(nobj.getObject()),ATTACH));
break;
case BEGIN:
axis.g2d = (Graph2D)graph;
axis.setTitleRotation(angle);
object.push(naxis);
while(attach.size() > 0) {
object.push(attach.pop());
}
built.addElement(axis);
applet.showStatus("BuildGraph: Built Axis!");
return true;
default:
errorAtLine("Incorrect keyword in Data specification");
return false;
}
}
}
/**
* @return true if the build was successful
*/
protected boolean buildGrid() {
NamedObject nobj;
NamedObject color = null;
NamedObject grid = null;
while( true ) {
nobj = (NamedObject)(object.pop());
debugMessage("Grid",nobj.id);
switch (nobj.id) {
case OFF:
grid = nobj;
grid.setId(GRID_OFF);
break;
case ON:
grid = nobj;
grid.setId(GRID_ON);
break;
case COLOR:
color = nobj;
color.setId(GRID_COLOR);
break;
case BEGIN:
if(grid != null) object.push(grid);
if(color != null) object.push(color);
return true;
default:
errorAtLine("Incorrect keyword in Grid specification");
return false;
}
}
}
/**
* @return true if the build was successful
*/
protected boolean buildZero() {
NamedObject nobj;
NamedObject color = null;
NamedObject zero = null;
while( true ) {
nobj = (NamedObject)(object.pop());
debugMessage("Zero",nobj.id);
switch (nobj.id) {
case OFF:
zero = nobj;
zero.setId(ZERO_OFF);
break;
case ON:
zero = nobj;
zero.setId(ZERO_ON);
break;
case COLOR:
color = nobj;
color.setId(ZERO_COLOR);
break;
case BEGIN:
if(zero != null) object.push(zero);
if(color != null) object.push(color);
return true;
default:
errorAtLine("Incorrect keyword in Zero specification");
return false;
}
}
}
/**
* output the parsed error message with the line number of the line
* that triggered the error.
* @param s Message to ouput
*/
private void errorAtLine(String s) {
System.out.println("Error at line "+lineno+": "+s);
applet.showStatus("Error at line "+lineno+": "+s);
}
/**
* output the parsed debug message, appending line number, and token string
* @param s Message to ouput
* @param token token to be replaced with a string
*/
private void debugMessage(String s, int token) {
String st = null;
if(!debug) return;
switch ( token ) {
case DEBUG:
st = null;
break;
case G2DINT:
st = "G2DINT";
break;
case GRAPH2D:
st = "GRAPH2D";
break;
case CONTOUR:
st = "CONTOUR";
break;
case TT_EOF:
st = null;
break;
case TT_EOL:
st = null;
break;
case URL:
st = "URL";
break;
case ATTACH:
st = "ATTACH";
break;
case STYLE:
st = "STYLE";
break;
case SIZE:
st = "SIZE";
break;
case COLOR:
st = "COLOR";
break;
case NAME:
st = "NAME";
break;
case BEGIN:
st = "BEGIN";
break;
case END:
st = "END";
break;
case MARKER:
st = "MARKER";
break;
case AXIS:
st = "AXIS";
break;
case TITLE:
st = "TITLE";
break;
case DATA:
st = "DATA";
break;
case LABEL:
st = "LABEL";
break;
case FONT:
st = "FONT";
break;
case BOTTOM:
st = "BOTTOM";
break;
case TOP:
st = "TOP";
break;
case LEFT:
st = "LEFT";
break;
case RIGHT:
st = "RIGHT";
break;
case ON:
st = "ON";
break;
case OFF:
st = "OFF";
break;
case PLAIN:
st = "PLAIN";
break;
case BOLD:
st = "BOLD";
break;
case ITALIC:
st = "ITALIC";
break;
case MARKER_STYLE:
st = "MARKER_STYLE";
break;
case MARKER_COLOR:
st = "MARKER_COLOR";
break;
case MARKER_SIZE:
st = "MARKER_SIZE";
break;
case LABEL_COLOR:
st = "LABEL_COLOR";
break;
case LABEL_FONT:
st = "LABEL_FONT";
break;
case GRID_COLOR:
st = "GRID_COLOR";
break;
case GRID:
st = "GRID";
break;
case GRID_OFF:
st = "GRID_OFF";
break;
case GRID_ON:
st = "GRID_ON";
break;
case ZERO_COLOR:
st = "ZERO_COLOR";
break;
case ZERO:
st = "ZERO";
break;
case ZERO_OFF:
st = "ZERO_OFF";
break;
case ZERO_ON:
st = "ZERO_ON";
break;
case MARKER_URL:
st = "MARKER_URL";
break;
case FUNCTION:
st = "FUNCTION";
break;
case XRANGE:
st = "XRANGE";
break;
case YRANGE:
st = "YRANGE";
break;
case NUMBER:
st = "NUMBER";
break;
case SQUARE:
st = "SQUARE";
break;
case BACKGROUND:
st = "BACKGROUND";
break;
default:
st = "UNKNOWN";
break;
}
if(st != null) System.out.println("("+lineno+") "+s+": "+st);
}
}
/**
* this is a structure class used exclusively BuildGraph.
* the class contains an Object variable, a String name identifying the object,
* and/or an integer token identifying the object.
*
*/
class NamedObject extends Object {
protected Object o = null;
protected String s = null;
protected int id = ScanWord.UNKNOWN;
public NamedObject() {
}
public NamedObject(Object o) {
this.o = o;
}
public NamedObject(Object o, String s) {
this.o = o;
this.s = s;
}
public NamedObject(Object o, String s, int id) {
this.o = o;
this.s = s;
this.id = id;
}
public NamedObject(Object o, int id) {
this.o = o;
this.id = id;
}
public NamedObject(int id) {
this.id = id;
}
public NamedObject(String s) {
this.s = s;
}
public Object getObject() { return o; }
public String getName() { return s; }
public int getId() { return id; }
public void setObject(Object o) {
this.o = o;
}
public void setId(int id) {
this.id = id;
}
public void setName(String s) {
this.s = s;
}
public boolean equals(Object obj) {
if(obj instanceof NamedObject) {
NamedObject nobj = (NamedObject)obj;
if( nobj.s == null && s != null ||
nobj.s != null && s == null ||
nobj.id != this.id ||
!nobj.s.equals(s) ) return false;
if( nobj.o.equals(o) ) return true;
}
return false;
}
}