/* * Adapted 10/98 by Sean Kessler * Added arrow key navigation * Added cell scrolling * Fixed drawing routines * Removed applet extension * Created Interface instantiation class with user interface methods * Fixed Strings * * @(#)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 SpreadSheetInterface { SpreadSheet mSpreadSheet; public SpreadSheetInterface(Applet applet,int rows,int columns) { mSpreadSheet=new SpreadSheet(applet,rows,columns,applet.size()); } public SpreadSheetInterface(Applet applet,int rows,int columns,Dimension controlDimension) { mSpreadSheet=new SpreadSheet(applet,rows,columns,controlDimension); } public void update(Graphics graphics) { mSpreadSheet.update(graphics); } public void paint(Graphics graphics) { mSpreadSheet.paint(graphics); } public boolean mouseDown(Event event,int x,int y) { return mSpreadSheet.mouseDown(event,x,y); } public boolean keyDown(Event event,int key) { return mSpreadSheet.keyDown(event,key); } public boolean setCellData(int row,int col,String strData) { return mSpreadSheet.setCellData(row,col,strData); } public boolean setCellData(int row,int col,String strData,boolean repaint) { return mSpreadSheet.setCellData(row,col,strData,repaint); } public void repaint() { mSpreadSheet.applet().repaint(); } public void setDocumentTitle(String strDocumentTitle) { mSpreadSheet.setDocumentTitle(strDocumentTitle); } public void clear() { mSpreadSheet.init(); } public void gridLock(boolean gridLock) { mSpreadSheet.gridLock(gridLock); } } class SpreadSheet { private final Dimension mCellDimension=new Dimension(100,15); private Dimension mControlDimension; private String mStrTitle; private Font mTitleFont; private Color mCellColor; private Color mInputColor; private int mTitleHeight=15; private int mRowLabelWidth=24; private boolean mIsStopped=false; private boolean mFullUpdate=true; private int mRows; private int mColumns; private int mSelectedRow; private int mSelectedColumn; private SpreadSheetInput mInputArea; private Cell mCells[][]; private Cell mCurrent=null; private int mStartDisplayRow; private int mStartDisplayColumn; private Applet mApplet; private boolean mGridLock; public SpreadSheet(Applet applet,int rows,int cols,Dimension controlDimension) { String strParam; mApplet=applet; mGridLock=false; mControlDimension=controlDimension; 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"; mRows=rows; mColumns=cols; mCells=new Cell[mRows][mColumns]; init(); mInputArea=new SpreadSheetInput(null,mApplet,this,mControlDimension.width-2,mCellDimension.height-1,mInputColor,Color.white); mApplet.resize(mColumns*mCellDimension.width+mRowLabelWidth,((mRows+1)*mCellDimension.height)+mCellDimension.height+mTitleHeight); } public void init() { char strLabel[]=new char[1]; deselect(true); for(int row=0;rowmControlDimension.height)continue; graphics.setColor(mApplet.getBackground()); graphics.draw3DRect(0,cy,mControlDimension.width,2,true); if(cy+mCellDimension.height>mControlDimension.height)continue; if(imControlDimension.width)continue; graphics.setColor(mApplet.getBackground()); graphics.draw3DRect(cx+mRowLabelWidth,2*mCellDimension.height,1,mControlDimension.height-(2*mCellDimension.height),true); } } public void drawCells(Graphics graphics,boolean updateAll) { int i; int j; int cx; int cy; boolean inDraw=true; for(i=mStartDisplayRow;imControlDimension.height)inDraw=false; if(mCells[i][j]!=null)mCells[i][j].paint(graphics,cx,cy); } } } } public void recalculate() { for(int row=0;row=mRows||mSelectedColumn>=mColumns) { mSelectedRow=-1; deselect(true); return true; } if(((mSelectedRow-mStartDisplayRow+2)*mCellDimension.height)+2+mTitleHeight>mControlDimension.height) { mSelectedRow=-1; deselect(true); return true; } if(((mSelectedColumn-mStartDisplayColumn)*mCellDimension.width)+2+mRowLabelWidth+mCellDimension.width>mControlDimension.width) { mSelectedColumn=-1; deselect(true); return true; } select(); return true; } public boolean keyDown(Event evt, int key) { if(Key.LeftArrow==key||Key.RightArrow==key||Key.UpArrow==key||Key.DownArrow==key) { if(!gridLock()){mInputArea.keyDown(Key.Return);mFullUpdate=true;} navigate(key); } else if(!gridLock()){mInputArea.keyDown(key);mFullUpdate=true;} return true; } private void navigate(int key) { switch(key) { case Key.LeftArrow : if(mSelectedColumn<=0)break; mSelectedColumn--; ensureVisible(); select(); break; case Key.RightArrow : if(mSelectedColumn+1>=mColumns)break; mSelectedColumn++; ensureVisible(); 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; } private void ensureVisible() { int yMin=(2*mCellDimension.height)+2+mTitleHeight; int xMin=2+mRowLabelWidth+mCellDimension.width; Point currPoint=new Point(0,0); currPoint.y=((mSelectedRow-mStartDisplayRow+2)*mCellDimension.height)+2+mTitleHeight; currPoint.x=((mSelectedColumn-mStartDisplayColumn)*mCellDimension.width)+2+mRowLabelWidth+mCellDimension.width; if(currPoint.y>mControlDimension.height)mStartDisplayRow++; else if(currPoint.ymControlDimension.width)mStartDisplayColumn++; else if(currPoint.x=mRows||col>=mColumns)return false; strCellData="l"; strCellData+=strData; mCells[row][col].setUnparsedValue(strCellData); if(repaint)mApplet.repaint(); return true; } public void setDocumentTitle(String strDocumentTitle) { mStrTitle=strDocumentTitle; } public void gridLock(boolean gridLock) { mGridLock=gridLock; } public boolean gridLock() { return mGridLock; } } //****************************************************************************************************** // ******************************************** 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 final int mMaxDisplayLength=14; 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 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 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(float value) { setRawValue(value); mPrintString="v"+mValueString; mType=Cell.VALUE; mPaused=false; mSpreadSheet.recalculate(); mNeedRedisplay=true; } public void setValue(int type, String s) { mPaused=false; 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; 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)return; 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; } String printString; if(!mTransientValue) { if(mValueString.length()>mMaxDisplayLength)printString=new String(mValueString.substring(0,mMaxDisplayLength)); else printString=new String(mValueString); } else printString=new String(""+mValue); FontMetrics metrics=graphics.getFontMetrics(); int stringWidth=metrics.stringWidth(printString); if(x+stringWidth=mMaxChars?mMaxChars-1:valLength,mBuffer,0); for(index=0;mBuffer[index]!=0&&index