Files
Work/java/SPREAD/HOLD/SPREAD~5.JAV
2024-08-07 09:16:27 -04:00

934 lines
24 KiB
Java

/*
* Adapted 10/98 by Sean Kessler
* Added arrow key navigation
* Added cell scrolling
*
* @(#)SpreadSheet.java 1.17 95/03/09 Sami Shaio
*
* Copyright (c) 1994-1995 Sun Microsystems, Inc. All Rights Reserved.
*
* Permission to use, copy, modify, and distribute this software
* and its documentation for NON-COMMERCIAL or COMMERCIAL purposes and
* without fee is hereby granted.
* Please refer to the file http://java.sun.com/copy_trademarks.html
* for further important copyright and trademark information and to
* http://java.sun.com/licensing.html for further important licensing
* information for the Java (tm) Technology.
*
* SUN MAKES NO REPRESENTATIONS OR WARRANTIES ABOUT THE SUITABILITY OF
* THE SOFTWARE, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
* TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
* PARTICULAR PURPOSE, OR NON-INFRINGEMENT. SUN SHALL NOT BE LIABLE FOR
* ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR
* DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES.
*
* THIS SOFTWARE IS NOT DESIGNED OR INTENDED FOR USE OR RESALE AS ON-LINE
* CONTROL EQUIPMENT IN HAZARDOUS ENVIRONMENTS REQUIRING FAIL-SAFE
* PERFORMANCE, SUCH AS IN THE OPERATION OF NUCLEAR FACILITIES, AIRCRAFT
* NAVIGATION OR COMMUNICATION SYSTEMS, AIR TRAFFIC CONTROL, DIRECT LIFE
* SUPPORT MACHINES, OR WEAPONS SYSTEMS, IN WHICH THE FAILURE OF THE
* SOFTWARE COULD LEAD DIRECTLY TO DEATH, PERSONAL INJURY, OR SEVERE
* PHYSICAL OR ENVIRONMENTAL DAMAGE ("HIGH RISK ACTIVITIES"). SUN
* SPECIFICALLY DISCLAIMS ANY EXPRESS OR IMPLIED WARRANTY OF FITNESS FOR
* HIGH RISK ACTIVITIES.
*/
import java.applet.Applet;
import java.awt.*;
import java.io.*;
import java.net.*;
//******************************************************************************************************
// ***************************************** SPREADSHEET ***********************************************
//******************************************************************************************************
//public class SpreadSheet extends Applet
public class SpreadSheet
{
private final Dimension mCellDimension=new Dimension(100,15);
private String mStrTitle;
private Font mTitleFont;
private Color mCellColor;
private Color mInputColor;
private int mTitleHeight=15;
private int mRowLabelWidth=15;
private boolean mIsStopped=false;
private boolean mFullUpdate=true;
private int mRows;
private int mColumns;
private int mSelectedRow = -1;
private int mSelectedColumn = -1;
private SpreadSheetInput mInputArea;
private Cell mCells[][];
private Cell mCurrent=null;
private int mStartDisplayRow;
private Applet mApplet;
public SpreadSheet(Applet applet)
{
String strParam;
mApplet=applet;
mStartDisplayRow=0;
mCellColor=Color.white;
mInputColor=new Color(100, 100, 225);
mTitleFont=new Font("Courier", Font.BOLD, 12);
mStrTitle=mApplet.getParameter("title");
if(null==mStrTitle)mStrTitle="SpreadSheet";
strParam=mApplet.getParameter("rows");
if(null==strParam)mRows=9;
else mRows=Integer.parseInt(strParam);
strParam=mApplet.getParameter("columns");
if(null==strParam)mColumns=5;
else mColumns=Integer.parseInt(strParam);
mCells=new Cell[mRows][mColumns];
char strLabel[]=new char[1];
for(int i=0; i < mRows; i++)
{
for (int j=0; j < mColumns; j++)
{
mCells[i][j]=new Cell(this,Color.lightGray,Color.black,mCellColor,mCellDimension.width-2,mCellDimension.height-2);
strLabel[0]=(char)((int)'a'+j);
strParam=mApplet.getParameter(""+new String(strLabel)+(i+1));
if(null!=strParam)mCells[i][j].setUnparsedValue(strParam);
}
}
Dimension workArea=mApplet.size();
mInputArea=new SpreadSheetInput(null,mApplet,this,workArea.width-2,mCellDimension.height-1,mInputColor,Color.white);
mApplet.resize(mColumns*mCellDimension.width+mRowLabelWidth,((mRows+1)*mCellDimension.height)+mCellDimension.height+mTitleHeight);
}
public void setCurrentValue(float val)
{
if(-1==mSelectedRow||-1==mSelectedColumn)return;
mCells[mSelectedRow][mSelectedColumn].setValue(val);
mApplet.repaint();
}
public void stop()
{
stopped(true);
}
public void start()
{
stopped(false);
}
public void stopped(boolean stopped)
{
mIsStopped=stopped;
}
public boolean stopped()
{
return mIsStopped;
}
public void destroy()
{
for(int i=0;i<mRows;i++)for(int j=0;j<mColumns;j++)if(mCells[i][j].type()==Cell.URL)mCells[i][j].cellThread().stop();
}
public void setCurrentValue(int type,String val)
{
if(-1==mSelectedRow||-1==mSelectedColumn)return;
mCells[mSelectedRow][mSelectedColumn].setValue(type,val);
mApplet.repaint();
}
public void update(Graphics graphics)
{
int cx;
int cy;
if(mFullUpdate)
{
paint(graphics);
mFullUpdate=false;
return;
}
graphics.setFont(mTitleFont);
for(int row=mStartDisplayRow;row<mRows;row++)
{
for(int col=0;col<mColumns;col++)
{
if(mCells[row][col].needRedisplay())
{
cx=(col*mCellDimension.width)+2+mRowLabelWidth;
cy=((row+1)*mCellDimension.height)+2+mTitleHeight;
mCells[row][col].paint(graphics,cx,cy);
}
}
}
}
public synchronized void paint(Graphics graphics)
{
int i;
int j;
int cx;
int cy;
char strLabel[]=new char[1];
Dimension clientRect=mApplet.size();
graphics.setFont(mTitleFont);
graphics.drawString(mStrTitle,(clientRect.width-graphics.getFontMetrics().stringWidth(mStrTitle))/2,12);
graphics.setColor(mInputColor);
graphics.fillRect(0,mCellDimension.height,clientRect.width,mCellDimension.height);
graphics.setFont(mTitleFont);
for(i=0;i<mRows+1;i++)
{
cy=(i+2)*mCellDimension.height;
graphics.setColor(mApplet.getBackground());
graphics.draw3DRect(0,cy,clientRect.width,2,true);
if(i<mRows)
{
graphics.setColor(mApplet.getBackground());
graphics.fillRect(1,cy+1,mRowLabelWidth-1,(2*mCellDimension.height)-2);
graphics.setColor(Color.red);
graphics.drawString(""+(i+1+mStartDisplayRow),2,cy+12);
}
}
graphics.setColor(Color.red);
for(i=0;i<mColumns;i++)
{
cx=i*mCellDimension.width;
graphics.setColor(mApplet.getBackground());
graphics.draw3DRect(cx+mRowLabelWidth,2*mCellDimension.height,1,clientRect.height,true);
}
for(i=mStartDisplayRow;i<mRows;i++)
{
for(j=0;j<mColumns;j++)
{
cx=(j*mCellDimension.width)+2+mRowLabelWidth;
cy=((i+1-mStartDisplayRow)*mCellDimension.height)+2+mTitleHeight;
if(mCells[i][j]!=null)mCells[i][j].paint(graphics,cx,cy);
}
}
graphics.setColor(mApplet.getBackground());
graphics.draw3DRect(0,mTitleHeight,clientRect.width,clientRect.height-mTitleHeight,false);
mInputArea.paint(graphics,1,mTitleHeight+1);
}
public void recalculate()
{
for(int row=0;row<mRows;row++)
{
for(int col=0;col<mColumns;col++)
{
if(mCells[row+mStartDisplayRow][col]!=null&&mCells[row+mStartDisplayRow][col].type()==Cell.FORMULA)
{
mCells[row+mStartDisplayRow][col].setRawValue(evaluateFormula(mCells[row+mStartDisplayRow][col].parseRoot()));
mCells[row+mStartDisplayRow][col].needRedisplay(true);
}
}
}
mApplet.repaint();
}
private float evaluateFormula(Node node)
{
float val=0.0f;
if(null==node)return val;
switch(node.type())
{
case Node.OP:
val=evaluateFormula(node.left());
switch(node.op())
{
case '+':
val += evaluateFormula(node.right());
break;
case '*':
val *= evaluateFormula(node.right());
break;
case '-':
val -= evaluateFormula(node.right());
break;
case '/':
val /= evaluateFormula(node.right());
break;
}
break;
case Node.VALUE:
val=node.value();
break;
case Node.CELL:
if(null==node)break;
if(null==mCells[node.row()][node.column()])break;
val=mCells[node.row()][node.column()].value();
break;
}
return val;
}
public boolean mouseDown(Event evt,int x,int y)
{
if(y<(mTitleHeight+mCellDimension.height))
{
mSelectedRow=-1;
if(y<=mTitleHeight)deselect(true);
return true;
}
if(x<mRowLabelWidth)
{
mSelectedRow=-1;
deselect(true);
return true;
}
mSelectedRow=((y-mCellDimension.height-mTitleHeight)/mCellDimension.height)+mStartDisplayRow;
mSelectedColumn=(x-mRowLabelWidth)/mCellDimension.width;
if(mSelectedRow>=mRows||mSelectedColumn>=mColumns)
{
mSelectedRow = -1;
deselect(true);
return true;
}
select();
return true;
}
public boolean keyDown(Event evt, int key)
{
mFullUpdate=true;
if(Key.LeftArrow==key||Key.RightArrow==key||Key.UpArrow==key||Key.DownArrow==key)
{
mInputArea.keyDown(Key.Return);
navigate(key);
}
else mInputArea.keyDown(key);
return true;
}
private void navigate(int key)
{
switch(key)
{
case Key.LeftArrow :
if(mSelectedColumn<=0)break;
mSelectedColumn--;
select();
break;
case Key.RightArrow :
if(mSelectedColumn>=mColumns)break;
mSelectedColumn++;
select();
break;
case Key.UpArrow :
if(mSelectedRow<=0)break;
mSelectedRow--;
ensureVisible();
select();
break;
case Key.DownArrow :
if(mSelectedRow+1>=mRows)break;
mSelectedRow++;
ensureVisible();
select();
break;
}
}
private void select()
{
Cell cell=mCells[mSelectedRow][mSelectedColumn];
if(null!=cell.getPrintString())mInputArea.setText(new String(cell.getPrintString()));
else mInputArea.setText(new String(""));
if(mCurrent!=null)mCurrent.deselect();
mCurrent=cell;
mCurrent.select();
mApplet.requestFocus();
mFullUpdate=true;
mApplet.repaint();
}
private void deselect(boolean destroy)
{
if(null==mCurrent)return;
mCurrent.deselect();
if(destroy)mCurrent=null;
}
public Applet applet()
{
return mApplet;
}
private boolean ensureVisible()
{
int yMin=(2*mCellDimension.height)+2+mTitleHeight;
Point currPoint=new Point(0,0);
Dimension workArea=mApplet.size();
boolean adjusted=false;
yMin=(2*mCellDimension.height)+2+mTitleHeight;
currPoint.y=((mSelectedRow-mStartDisplayRow+2)*mCellDimension.height)+2+mTitleHeight;
currPoint.x=(mSelectedColumn*mCellDimension.width)+2+mRowLabelWidth;
if(currPoint.y>workArea.height){mStartDisplayRow++;adjusted=true;}
else if(currPoint.y<yMin){mStartDisplayRow--;adjusted=true;}
return adjusted;
}
}
//******************************************************************************************************
// ***************************************** CELLTHREAD ***********************************************
//******************************************************************************************************
class CellThread extends Thread
{
private Cell mTarget;
private InputStream mDataStream=null;
private StreamTokenizer mTokenStream;
public CellThread(Cell cell)
{
super("CellThread");
mTarget=cell;
}
public void run()
{
try
{
mDataStream = new URL(mTarget.spreadSheet().applet().getDocumentBase(),mTarget.getValueString()).openStream();
mTokenStream = new StreamTokenizer(mDataStream);
mTokenStream.eolIsSignificant(false);
while(true)
{
switch(mTokenStream.nextToken())
{
case mTokenStream.TT_EOF:
mDataStream.close();
return;
default:
break;
case mTokenStream.TT_NUMBER:
mTarget.setTransientValue((float)mTokenStream.nval);
if(!mTarget.spreadSheet().stopped()&&!mTarget.paused())mTarget.spreadSheet().applet().repaint();
break;
}
try {Thread.sleep(2000);}
catch(InterruptedException exception){break;}
}
}
catch (IOException exception){return;}
}
}
//******************************************************************************************************
// ******************************************** CELL ***************************************************
//******************************************************************************************************
class Cell
{
public static final int VALUE = 0;
public static final int LABEL = 1;
public static final int URL = 2;
public static final int FORMULA = 3;
private Node mParseRoot;
private boolean mNeedRedisplay;
private boolean mSelected = false;
private boolean mTransientValue = false;
private int mType=Cell.VALUE;
private String mValueString = "";
private String mPrintString = "v";
private float mValue;
private Color mBgColor;
private Color mFgColor;
private Color mHighlightColor;
private int mWidth;
private int mHeight;
private SpreadSheet mSpreadSheet;
private CellThread mCellThread;
private boolean mPaused=false;
public Cell(SpreadSheet spreadSheet,Color bgColor,Color fgColor,Color highlightColor,int width,int height)
{
mSpreadSheet=spreadSheet;
mBgColor=bgColor;
mFgColor=fgColor;
mHighlightColor=highlightColor;
mWidth=width;
mHeight=height;
mNeedRedisplay=true;
}
public void setRawValue(float value)
{
mValueString=Float.toString(value);
mValue=value;
}
public void setValue(float value)
{
setRawValue(value);
mPrintString="v"+mValueString;
mType=Cell.VALUE;
mPaused=false;
mSpreadSheet.recalculate();
mNeedRedisplay=true;
}
public void setTransientValue(float value)
{
mTransientValue=true;
mValue=value;
mNeedRedisplay=true;
mSpreadSheet.recalculate();
}
public void setUnparsedValue(String s)
{
switch (s.charAt(0))
{
case 'v':
setValue(Cell.VALUE, s.substring(1));
break;
case 'f':
setValue(Cell.FORMULA, s.substring(1));
break;
case 'l':
setValue(Cell.LABEL, s.substring(1));
break;
case 'u':
setValue(Cell.URL, s.substring(1));
break;
}
}
public String parseFormula(String formula, Node node)
{
String subformula;
String restFormula;
float value;
int length = formula.length();
Node left;
Node right;
char op;
if(null==formula)return null;
subformula=parseValue(formula, node);
if(null==subformula||0==subformula.length())return null;
if(subformula==formula)return formula;
switch(op=subformula.charAt(0))
{
case 0:
return null;
case ')':
return subformula;
case '+':
case '*':
case '-':
case '/':
restFormula = subformula.substring(1);
subformula = parseValue(restFormula, right=new Node());
if(subformula != restFormula)
{
left = new Node(node);
node.left(left);
node.right(right);
node.op(op);
node.type(Node.OP);
return subformula;
}
else return formula;
default:
return formula;
}
}
public String parseValue(String formula, Node node)
{
char c=formula.charAt(0);
String subformula;
String restFormula;
float value;
int row;
int column;
restFormula = formula;
if (c == '(')
{
restFormula = formula.substring(1);
subformula = parseFormula(restFormula, node);
if(subformula == null || subformula.length() == restFormula.length())return formula;
else if (! (subformula.charAt(0) == ')'))return formula;
restFormula = subformula;
}
else if (c >= '0' && c <= '9')
{
int i;
try{value = Float.valueOf(formula).floatValue();}
catch (NumberFormatException exception){return formula;}
for (i=0; i < formula.length(); i++)
{
c = formula.charAt(i);
if ((c < '0' || c > '9') && c != '.')break;
}
node.type(Node.VALUE);
node.value(value);
restFormula = formula.substring(i);
return restFormula;
}
else if (c >= 'A' && c <= 'Z')
{
int i;
column = c - 'A';
restFormula = formula.substring(1);
row = Float.valueOf(restFormula).intValue();
for(i=0; i < restFormula.length(); i++)
{
c = restFormula.charAt(i);
if (c < '0' || c > '9')break;
}
node.row(row-1);
node.column(column);
node.type(Node.CELL);
if (i == restFormula.length())restFormula=null;
else
{
restFormula = restFormula.substring(i);
if (restFormula.charAt(0) == 0)return null;
}
}
return restFormula;
}
public void setValue(int type, String s)
{
mPaused=false;
if(mType == Cell.URL)
{
mCellThread.stop();
mCellThread=null;
}
mValueString=new String(s);
mType=type;
mNeedRedisplay=true;
switch(mType)
{
case Cell.VALUE:
setValue(Float.valueOf(s).floatValue());
break;
case Cell.LABEL:
mPrintString = "l" + mValueString;
break;
case Cell.URL:
mPrintString = "u" + mValueString;
mCellThread = new CellThread(this);
mCellThread.start();
break;
case Cell.FORMULA:
parseFormula(mValueString,mParseRoot=new Node());
mPrintString = "f" + mValueString;
break;
}
mSpreadSheet.recalculate();
}
public String getValueString()
{
return mValueString;
}
public String getPrintString()
{
return mPrintString;
}
public void select()
{
mSelected=true;
mPaused=true;
}
public void deselect()
{
mSelected=false;
mPaused=false;
mNeedRedisplay=true;
mSpreadSheet.applet().repaint();
}
public void paint(Graphics graphics,int x,int y)
{
if(mSelected)graphics.setColor(mHighlightColor);
else graphics.setColor(mBgColor);
graphics.fillRect(x+1,y+1,mWidth-1,mHeight-1);
if(null!=mValueString)
{
switch(mType)
{
case Cell.VALUE:
case Cell.LABEL:
graphics.setColor(mFgColor);
break;
case Cell.FORMULA:
graphics.setColor(Color.red);
break;
case Cell.URL:
graphics.setColor(Color.blue);
break;
}
if(!mTransientValue)
{
if(mValueString.length()>14)graphics.drawString(mValueString.substring(0,14),x,y+(mHeight/2)+5);
else graphics.drawString(mValueString,x,y+(mHeight/2)+5);
}
else graphics.drawString(""+mValue,x,y+(mHeight/2)+5);
mNeedRedisplay=false;
}
}
public int type()
{
return mType;
}
public Node parseRoot()
{
return mParseRoot;
}
public void needRedisplay(boolean needRedisplay)
{
mNeedRedisplay=needRedisplay;
}
public boolean needRedisplay()
{
return mNeedRedisplay;
}
public float value()
{
return mValue;
}
public CellThread cellThread()
{
return mCellThread;
}
public SpreadSheet spreadSheet()
{
return mSpreadSheet;
}
public boolean paused()
{
return mPaused;
}
}
//******************************************************************************************************
// *************************************** NODE *******************************************************
//******************************************************************************************************
class Node
{
public static final int OP = 0;
public static final int VALUE = 1;
public static final int CELL = 2;
private int mType;
private Node mLeft;
private Node mRight;
private int mRow;
private int mColumn;
private float mValue;
private char mOp;
public Node()
{
mLeft=null;
mRight=null;
mValue=0;
mRow=-1;
mColumn=-1;
mOp=0;
mType=Node.VALUE;
}
public Node(Node node)
{
mLeft=node.mLeft;
mRight=node.mRight;
mValue=node.mValue;
mRow=node.mRow;
mColumn=node.mColumn;
mOp=node.mOp;
mType=node.mType;
}
public void print(int indentLevel)
{
char l[] = new char[1];
switch(mType)
{
case Node.VALUE:
break;
case Node.CELL:
l[0] = (char)((int)'A' + column());
break;
case Node.OP:
mLeft.print(indentLevel + 3);
mRight.print(indentLevel + 3);
break;
}
}
public int type()
{
return mType;
}
public void type(int type)
{
mType=type;
}
public float value()
{
return mValue;
}
public void value(float value)
{
mValue=value;
}
public Node left()
{
return mLeft;
}
public void left(Node left)
{
mLeft=left;
}
public Node right()
{
return mRight;
}
public void right(Node right)
{
mRight=right;
}
public char op()
{
return mOp;
}
public void op(char op)
{
mOp=op;
}
public int row()
{
return mRow;
}
public void row(int row)
{
mRow=row;
}
public int column()
{
return mColumn;
}
public void column(int column)
{
mColumn=column;
}
}
class InputField
{
private int mMaxchars = 50;
private Applet mApplet;
private String mStringValue;
private char mBuffer[];
private int mChars;
private int mWidth;
private int mHeight;
private Color mBgColor;
private Color mFgColor;
public InputField(String initValue,Applet applet,int width,int height,Color bgColor, Color fgColor)
{
mWidth=width;
mHeight=height;
mBgColor=bgColor;
mFgColor=fgColor;
mApplet=applet;
mBuffer = new char[mMaxchars];
mChars = 0;
if(initValue != null)
{
initValue.getChars(0, initValue.length(),mBuffer, 0);
mChars = initValue.length();
}
mStringValue=initValue;
}
public void setText(String val)
{
int i;
for(i=0; i < mMaxchars; i++)mBuffer[i] = 0;
mStringValue=new String(val);
if (val == null)
{
mStringValue= "";
mChars = 0;
mBuffer[0] = 0;
}
else
{
mStringValue.getChars(0,mStringValue.length(), mBuffer, 0);
mChars = val.length();
mStringValue = new String(mBuffer);
}
}
public String getValue()
{
return mStringValue;
}
public void paint(Graphics g, int x, int y)
{
g.setColor(mBgColor);
g.fillRect(x, y,mWidth,mHeight);
if(mStringValue!= null)
{
g.setColor(mFgColor);
g.drawString(mStringValue, x, y + (mHeight / 2) + 3);
}
}
public void mouseUp(int x, int y)
{
}
public void keyDown(int key)
{
if(mChars<mMaxchars)
{
switch(key)
{
case Key.BackSpace :
--mChars;
if(mChars<0)mChars=0;
mBuffer[mChars] = 0;
mStringValue = new String(new String(mBuffer));
break;
case Key.Return :
selected();
break;
default:
mBuffer[mChars++] = (char)key;
mStringValue = new String(new String(mBuffer));
break;
}
}
mApplet.repaint();
}
public void selected()
{
}
public Applet applet()
{
return mApplet;
}
}
class SpreadSheetInput extends InputField
{
SpreadSheet mSpreadSheet;
public SpreadSheetInput(String initValue,Applet app,SpreadSheet spreadSheet,int width,int height,Color bgColor,Color fgColor)
{
super(initValue,app,width,height,bgColor,fgColor);
mSpreadSheet=spreadSheet;
}
public void selected()
{
float f;
switch(getValue().charAt(0))
{
case 'v':
try{f=Float.valueOf(getValue().substring(1)).floatValue();mSpreadSheet.setCurrentValue(f);}
catch(Exception exception){;}
break;
case 'l':
mSpreadSheet.setCurrentValue(Cell.LABEL,getValue().substring(1));
break;
case 'u':
mSpreadSheet.setCurrentValue(Cell.URL,getValue().substring(1));
break;
case 'f':
mSpreadSheet.setCurrentValue(Cell.FORMULA,getValue().substring(1));
break;
}
}
}
class Key
{
public static final int LeftArrow=1006;
public static final int RightArrow=1007;
public static final int UpArrow=1004;
public static final int DownArrow=1005;
public static final int BackSpace=8;
public static final int Return=10;
public Key()
{
}
};