/* ArgValue.java Author Casey Hopson
* Geist Software and Services, Inc.
*
* Permission to use, copy, modify, and distribute
* this software for NON_COMMERCIAL purposes and without
* fee is hereby granted provided that this copyright notice
* appears in all copies.
*
* The creators of this software make no representations or
* warranties about the suitability of the software, either
* express or implied. The creators shall not be liable for
* any damages suffered by licensee as a result of using,
* modifying or distributing this software or its derivatives.
*/
import java.lang.*;
// This object contains variables that are used to define
// parameters about an argument value...
public class ArgValue {
public final static int UNDEFINED = 0;
public final static int LITERAL = 1;
public final static int CELL = 2;
int type;
double litValue; // For literal values...
int row; // For cell values...
int column;
public ArgValue() {
type = UNDEFINED;
}
// Set arguments if it is literal...
public void setLiteral(double val) {
type = LITERAL;
litValue = val;
}
// Set arguments if it is a cell...
public void setCell(int row, int column) {
type = CELL;
this.row = row;
this.column = column;
}
// Return literal...
public double getLiteral() {
return litValue;
}
// Return cell values...
public int getRow() {
return row;
}
public int getColumn() {
return column;
}
// Get the type...
public int getType() {
return type;
}
}
===========================================
/* Cell.java Author Casey Hopson
* Geist Software and Services, Inc.
*
* Permission to use, copy, modify, and distribute
* this software for NON_COMMERCIAL purposes and without
* fee is hereby granted provided that this copyright notice
* appears in all copies.
*
* The creators of this software make no representations or
* warranties about the suitability of the software, either
* express or implied. The creators shall not be liable for
* any damages suffered by licensee as a result of using,
* modifying or distributing this software or its derivatives.
*/
// This file describes the Cell class that contains
// a string formula and evaluated value for an individual cell
import java.lang.*;
// A cell contains the formula about for an individual cell
// However, it does not know what to do with it and simply
// returns its contents...
public class Cell {
String s;
double evaluatedValue;
boolean evaluated; // True if the cell has been evaluated
// Constructor creates empty StringBuffer as reference...
public Cell() {
s = "";
evaluatedValue = 0.0;
evaluated = true;
}
// Takes a StringBuffer and makes it the cell's data...
public void setCellString(StringBuffer s) {
this.s = new String(s);
evaluated = false;
}
// Takes a StringBuffer and makes it the cell's data...
public void setCellString(String s) {
this.s = s;
evaluated = false;
}
// Return the current contents of the Cell
public String getCellString() {
return s;
}
// Set the evaluated value of a cell...
public void setEvalValue(double val) {
evaluated = true;
evaluatedValue = val;
}
// Set the evaluated value of a cell...
public void setEvalValue(int val) {
setEvalValue((double)val);
}
// See if a cell has been evaluated...
public boolean getEvaluated() {
return evaluated;
}
// Get the evaluated value of a cell...
public double getEvalValue() {
return evaluatedValue;
}
// Set a cell to unevaluated...
public void setEvaluated(boolean eval) {
evaluated = eval;
}
}
===========================================
/* CellContainer.java Author Casey Hopson
* Geist Software and Services, Inc.
*
* Permission to use, copy, modify, and distribute
* this software for NON_COMMERCIAL purposes and without
* fee is hereby granted provided that this copyright notice
* appears in all copies.
*
* The creators of this software make no representations or
* warranties about the suitability of the software, either
* express or implied. The creators shall not be liable for
* any damages suffered by licensee as a result of using,
* modifying or distributing this software or its derivatives.
*/
// This file describes the CellContainer class that contains
// a matrix of Cell data. It is responsible for making sure
// that the formulas in the cells are evaluated properly...
import java.lang.*;
import java.io.*;
// The CellContainer class contains a matrix of Cell data.
// The class is responsible for making sure
// that the formulas in the cells are evaluated properly...
public class CellContainer {
int numRows; // Number of rows in container...
int numColumns; // Number of columns...
Cell matrix[]; // Matrix of row/column Cells...
int magicNumber = 0xF1082920;
char delimiter = '\t'; // Save files a tab delimited...
int maxRows = 25; // Default maximum sizes...
int maxColumns = 40;
// Constructs an empty container...
public CellContainer() {
numRows = 0;
numColumns = 0;
matrix = null;
}
// Constructs a matrix of cells [rows X columns]
public CellContainer(int rows,int columns) throws IllegalArgumentException {
numRows = rows;
numColumns = columns;
// Throw an exception if the row/col values are no good...
if ((numRows <= 0) || (numColumns <=0) ||
(numRows > maxRows) || (numColumns > maxColumns) ) {
numRows = 0;
numColumns = 0;
matrix = null;
throw new IllegalArgumentException();
}
// Create the Cell matrix...
int numCells = numRows * numColumns;
matrix = new Cell[numCells];
for (int i = 0; i < numCells; ++i)
matrix[i] = new Cell();
}
// Save the cell container to a file...
// Constructs the matrix by reading in data from the
// given filename...
public CellContainer(String filename) throws IOException {
// Call the code to read in a file
// It will throw an exception if the data is bad...
readFile(filename);
}
// Sets the new value of a cell...
public void setCellFormula(StringBuffer s,int row,int col) {
setCellFormula(s.toString(),row,col);
}
// Sets the new value of a cell...
public void setCellFormula(String s,int row,int col) {
// Get the index into the matrix...
int index;
try {
index = getMatrixIndex(row,col);
}
catch (IllegalArgumentException e) {
System.out.println("Invalid CellContainer index.");
return;
}
// Set the value of the cell...
matrix[index].setCellString(s);
}
// Get the string contents of a cell...
public String getCellFormula(int row,int col) throws IllegalArgumentException {
// Get the index into the matrix...
int index;
try {
index = getMatrixIndex(row,col);
}
catch (IllegalArgumentException e) {
throw e;
}
// Good index. Return string...
return matrix[index].getCellString();
}
// Get the cell at certain index...
public Cell getCell(int row,int col) throws IllegalArgumentException {
// Get the index into the matrix...
int index;
try {
index = getMatrixIndex(row,col);
}
catch (IllegalArgumentException e) {
throw e;
}
// Good index. Return Cell...
return matrix[index];
}
// Calculate the matrix index given a row and column...
// Throw an exception if it is bad...
int getMatrixIndex(int row,int col) throws IllegalArgumentException {
// Kick out if there are negative indexes...
if ((row < 0) || (col <0))
throw new IllegalArgumentException();
// Also reject too large indexes...
if ((row >= numRows) || (col >= numColumns))
throw new IllegalArgumentException();
// Everything is ok. Calculate index...
return ((numColumns * row) + col);
}
// Validate a formula by seeing if it matches the basic syntax...
public String validateFormula(Cell c,String newFormula) throws FormulaParserException {
// Convert all alphas to Upper Case
String convertedFormula = newFormula.toUpperCase();
// Get old formula of cell and temporarily set cell value there...
String oldFormula = c.getCellString();
// Setup the parser to validate the cell...
FormulaParser f = new FormulaParser(convertedFormula);
// Validate the cell...
try { // Set up the formula parser...
// Get the type of formula it is...
int typeFormula = f.getType();
// If its empty return Success...
if (typeFormula == f.EMPTY)
return convertedFormula;
// Check to see if literal is valid...
if (typeFormula == f.LITERAL) {
f.getLiteral(); // Ignore the return value...
return convertedFormula;
} // end if
// If its a formula we need to parse it...
parseFormula(c,f);
}
catch (Exception e) {
throw new FormulaParserException();
}
// Return the converted string...
return convertedFormula;
}
// Recalculate the values in all of the cells...
public void recalculateAll() {
if (matrix == null)
return;
// Invalidate the formulas...
invalidateFormulas();
// Go through each cell and calculate its value...
// Go row-wise across as this is how things probably are setup
int i,j;
for (i = 0; i < numRows; ++i) {
for (j = 0; j < numColumns; ++j) {
if (matrix[(i * numColumns) + j].getEvaluated() == false) {
calculateCell(i,j);
}
} // end column for
} // end row for
}
// Recalculate an individual cell...
// Update its evaluation when complete...
double calculateCell(int row,int col) {
// Get the index of the calculation...
int index;
try {
index = getMatrixIndex(row,col);
}
catch (IllegalArgumentException e) {
return 0.0; // Bad index...
}
// Setup the parser to recalculate the cell...
FormulaParser f = new FormulaParser(matrix[index].getCellString());
// First get the type...
int typeFormula = f.getType();
// If its empty, we're done...
if (typeFormula == f.EMPTY) {
matrix[index].setEvalValue(0.0);
return 0.0;
}
// If its a literal, we can also finish quickly...
if (typeFormula == f.LITERAL) {
// It better be some kind of number...
try {
double dbl = f.getLiteral(); // Get the double value...
matrix[index].setEvalValue(dbl);
return dbl;
}
// Some kind of invalid string...
catch(FormulaParserException e) {
System.out.println("Invalid literal at [" + row + "," + col + "]");
matrix[index].setEvalValue(0.0);
return 0.0;
}
}
// Formulas got to be parsed and maybe recurse, however...
double dbl;
try {
dbl = parseFormula(matrix[index],f);
}
catch (Exception e) {
System.out.println("Invalid formula at [ " + row + "," + col + "]");
dbl = 0.0;
}
matrix[index].setEvalValue(dbl);
System.out.println("Eval at [ " + row + "," + col + "] = " + dbl);
return dbl;
}
// Parse out a formula...
// Assumes formula parser is set to a certain formula...
double parseFormula(Cell c, FormulaParser f) throws FormulaParserException {
// Figure out what type of formula it is...
try {
int op = f.getOperation();
// Get the arguments...
ArgValue arg1 = new ArgValue();
ArgValue arg2 = new ArgValue();
f.getOpArgs(arg1,arg2);
// Sum operation is different from rest...
if (op != f.SUM) { // SUM is even worse...
double val1,val2;
// Get the values...
// See if we have to recurse...
if (arg1.getType() == arg1.CELL)
val1 = calculateCell(arg1.getRow(),arg1.getColumn());
else
val1 = arg1.getLiteral();
if (arg2.getType() == arg1.CELL)
val2 = calculateCell(arg2.getRow(),arg2.getColumn());
else
val2 = arg2.getLiteral();
System.out.println("Val1 = " + val1 + " Val2 = " + val2);
// Perform the operation...
switch (op) {
case f.ADD:
return (val1 + val2);
case f.MULT:
return (val1 * val2);
case f.DIV:
try {
double ret = val1 / val2;
return ret;
}
catch (ArithmeticException e) {
// Divide by zero!
return 0.0;
}
case f.SUB:
return (val1 - val2);
default:
break;
} // end switch...
} // end if
else { // Sum...
double dbl = 0.0;
int index;
if ((arg1.getType() != arg1.CELL) || (arg2.getType() != arg2.CELL))
throw new FormulaParserException();
// Row-wise or column wise...
if (arg1.getRow() == arg2.getRow()) {
if (arg2.getColumn() < arg1.getColumn())
throw new FormulaParserException();
for (int i = arg1.getColumn(); i <= arg2.getColumn(); ++i) {
// Skip cases where the cells are the same...
index = getMatrixIndex(arg2.getRow(),i);
if (matrix[index] == c)
continue;
// If Ok, then recurse...
dbl += calculateCell(arg2.getRow(),i);
} // end for
return dbl;
}
else if (arg1.getColumn() == arg2.getColumn()) {
if (arg2.getRow() < arg1.getRow())
throw new FormulaParserException();
for (int i = arg1.getRow(); i <= arg2.getRow(); ++i) {
// Skip cases where the cells are the same...
index = getMatrixIndex(i,arg2.getColumn());
if (matrix[index] == c)
continue;
// If Ok, then recurse...
dbl += calculateCell(i,arg2.getColumn());
} // end for
return dbl;
}
throw new FormulaParserException();
}
return 0.0;
}
catch (FormulaParserException e) {
throw e;
}
}
// Invalidate all cells that are formulas to force recalculation...
void invalidateFormulas() {
// Setup the parser to get the cell type...
FormulaParser f = new FormulaParser();
int numCells = numRows * numColumns;
for (int i = 0; i < numCells; ++i) {
f.setFormula(matrix[i].getCellString());
if (f.getType() == f.FORMULA)
matrix[i].setEvaluated(false);
} // end for
}
// Get the number of rows in the container
int getNumRows() {
return numRows;
}
// Get the number of columns in the container
int getNumColumns() {
return numColumns;
}
// Read in a file and create a new matrix to
// accomodate the data...
public void readFile(String filename) throws IOException {
// Set everything to empty...
numRows = 0;
numColumns = 0;
int magic;
byte b;
DataInputStream fs;
try {
// Open the file...
fs = new DataInputStream(new BufferedInputStream(
new FileInputStream(filename)) );
}
// Can't open file, quit out...
catch (IOException e) {
throw e;
}
// Now try to load the data...
try {
// Check the magic number
magic = fs.readInt();
if (magic != magicNumber)
throw (new IOException("Invalid magic number"));
// Get the rows and columns...
numRows = fs.readInt();
numColumns = fs.readInt();
if ((numRows <= 0) || (numColumns <=0) ||
(numRows > maxRows) || (numColumns > maxColumns) )
throw (new IOException("Invalid row/col settings"));
int numCells = numRows * numColumns;
// Allocate matrix...
matrix = new Cell[numCells];
// Now load the individual cells...
for (int i = 0; i < numCells; ++i) {
// Load the string up until delimited...
StringBuffer s = new StringBuffer();
while ((b = fs.readByte()) != delimiter)
s.append((char)b);
// Add it to new Cell...
matrix[i] = new Cell();
matrix[i].setCellString(s);
} // end for
// Success! Close the file and leave...
fs.close();
}
// If exception then close file,
// and reset everything...
catch (IOException e) {
numRows = 0;
numColumns = 0;
fs.close();
throw e;
}
}
// Save the cell container to a file...
public void saveFile(String filename) throws IOException {
// Perform these file operations. If anything goes wrong
// an exception will be thrown. This must be caught
// by the calling method...
// Open the file...
DataOutputStream fs = new DataOutputStream(
// !! Insert BufferedOutput here!!
new FileOutputStream(filename));
// Write out magic number
fs.writeInt(magicNumber);
// Write out row and column sizes
fs.writeInt(numRows);
fs.writeInt(numColumns);
// Now go through each row and column and save...
// Write out literal value followed by delimited...
int numCells = numRows * numColumns;
for (int i = 0; i < numCells; ++i) {
fs.writeBytes(matrix[i].getCellString());
fs.writeByte(delimiter);
} // end for
// Close the file. We're done!
fs.close();
}
}
========================================================
/* ChooseColorDialog.java Author Casey Hopson
* Geist Software and Services, Inc.
*
* Permission to use, copy, modify, and distribute
* this software for NON_COMMERCIAL purposes and without
* fee is hereby granted provided that this copyright notice
* appears in all copies.
*
* The creators of this software make no representations or
* warranties about the suitability of the software, either
* express or implied. The creators shall not be liable for
* any damages suffered by licensee as a result of using,
* modifying or distributing this software or its derivatives.
*/
import java.awt.*;
import java.lang.*;
// Dialog box for choosing display colors...
public class ChooseColorDialog extends Dialog {
SpreadsheetFrame fr; // What to update...
ColoredCheckboxGroup colorGrp; // To hold radio buttons of colors...
SpreadsheetContainer s;
List choiceList; // List of color choices...
colorDisplay d; // This is the text display...
// Defines for listbox values...
static int NORMAL_FORE = 0;
static int NORMAL_BACK = 1;
static int HILITE_FORE = 2;
static int HILITE_BACK = 3;
// Construct dialog to allow color to be chosen...
public ChooseColorDialog(Frame parent,boolean modal) {
// Create dialog with title
super(parent,"Color Dialog",modal);
fr = (SpreadsheetFrame)parent;
// Create the dialog components...
createComponents();
pack(); // Compact...
// Resize to fit everything...
resize(preferredSize());
}
// Wait for Cancel or OK buttons to be chosen...
public boolean handleEvent(Event e) {
switch(e.id) {
case Event.ACTION_EVENT:
// Kill the dialog...
if (e.arg.equals("Cancel")) {
dispose(); // Remove Dialog...
return true;
} // end if
// Update colors on the spreadsheet...
if (e.arg.equals("Update")) {
setSpreadsheetColors();
return true;
} // end if
if (e.target instanceof Checkbox) {
selectedRadioItem();
return false;
}
return false;
// User selected a listbox item...
case Event.LIST_SELECT:
// Set up caption colors and color choice highlight...
if (e.target instanceof List) {
selectedChoiceListItem();
return false;
} // end list if
return false;
default:
return false;
} // end switch
}
// The layout will call this to get the preferred size
// of the dialog. Make it big enough for the listbox text
// the checkboxes, canvas, and buttons...
public Dimension preferredSize() {
// Get the metrics of the current font...
FontMetrics fm = getFontMetrics(getFont());
int width = 3 * fm.stringWidth("Highlighted foreground");
int height = 24 * fm.getHeight();
return new Dimension(width,height);
}
// Create the main display panel...
void createComponents() {
// Use gridbag constraints...
GridBagLayout g = new GridBagLayout();
setLayout(g);
GridBagConstraints gbc = new GridBagConstraints();
// Set the constraints for the top objects...
gbc.fill = GridBagConstraints.BOTH;
gbc.weightx = 1.0;
gbc.weighty = 1.0;
gbc.gridheight = 10;
// Add the listbox of choices...
choiceList = new List();
choiceList.addItem("Normal foreground");
choiceList.addItem("Normal background");
choiceList.addItem("Highlighted foreground");
choiceList.addItem("Highlighted background");
g.setConstraints(choiceList,gbc);
add(choiceList);
// Create the checkbox panel
Panel checkboxPanel = new Panel();
checkboxPanel.setLayout(new GridLayout(12,1));
// Create the checkbox group and add radio buttons...
colorGrp = new ColoredCheckboxGroup(checkboxPanel);
colorGrp.setMatchingColor(Color.magenta);
// Create add checkbox panel to right...
gbc.gridwidth = GridBagConstraints.REMAINDER;
g.setConstraints(checkboxPanel,gbc);
add(checkboxPanel);
// Display the color chosen...
d = new colorDisplay("This is how the text looks.");
// Add to grid bag...
gbc.weighty = 0.0;
gbc.weightx = 1.0;
gbc.gridwidth = GridBagConstraints.REMAINDER;
gbc.gridheight = 1;
g.setConstraints(d,gbc);
add(d);
// Two buttons: "Update" and "Cancel"
Panel p = new Panel();
p.add(new Button("Update"));
p.add(new Button("Cancel"));
// Add to grid bag...
gbc.gridwidth = GridBagConstraints.REMAINDER;
g.setConstraints(p,gbc);
add(p);
}
// Setup defaults upon showing...
public synchronized void show() {
super.show(); // Call the default constructor...
// Get the spreadsheet container...
s = fr.getSpreadsheetContainer();
// Set the listbox default...
choiceList.select(0);
// Set up caption colors and color choice highlight...
selectedChoiceListItem();
}
// Set up caption colors and color choice highlight
// according to current listbox value...
private void selectedChoiceListItem() {
Color fore,back; // Display canvas colors
// If normal set canvas colors...
int index = choiceList.getSelectedIndex();
if ((index == NORMAL_FORE) || (index == NORMAL_BACK)) {
fore = s.getNormalForeColor();
back = s.getNormalBackColor();
}
// Otherwise its the background...
else {
fore = s.getHighlightedForeColor();
back = s.getHighlightedBackColor();
}
// Update the canvas...
d.setForeColor(fore);
d.setBackColor(back);
d.repaint();
// Update the color radio buttons...
Color radioColor;
// Even numbers are fore, odd are back...
if ((index % 2) == 0)
radioColor = fore;
else
radioColor = back;
colorGrp.setMatchingColor(radioColor);
}
// Update display canvas when radio color changes...
private void selectedRadioItem() {
// Get choice from Color box...
ColoredCheckbox box = (ColoredCheckbox)colorGrp.getCurrent();
Color color = box.getColor();
// If normal set canvas colors...
Color fore,back;
int index = choiceList.getSelectedIndex();
// Set background or foreground color based on
// current listbox selection...
if ((index == NORMAL_FORE) || (index == HILITE_FORE))
d.setForeColor(color);
else
d.setBackColor(color);
// Repaint the canvas...
d.repaint();
}
// Update the spreadsheet colors...
public void setSpreadsheetColors() {
// Store all the default colors...
Color normalFore,normalBack;
Color hiliteFore,hiliteBack;
normalFore = s.getNormalForeColor();
normalBack = s.getNormalBackColor();
hiliteFore = s.getHighlightedForeColor();
hiliteBack = s.getHighlightedBackColor();
// Get choice from Color box...
ColoredCheckbox box = (ColoredCheckbox)colorGrp.getCurrent();
Color color = box.getColor();
// Get the current selection...
int index = choiceList.getSelectedIndex();
if (index == NORMAL_FORE)
normalFore = color;
else if (index == NORMAL_BACK)
normalBack = color;
else if (index == HILITE_FORE)
hiliteFore = color;
else
hiliteBack = color;
// Update the spreadsheet!
s.setNewColors(normalFore,normalBack,hiliteFore,hiliteBack);
}
}
// A small class that illustrates the
// current highlight and background
class colorDisplay extends Canvas {
String displayText;
Color foreground; // The colors to be displayed...
Color background;
// Construct the display by storing the
// text to be displayed...
public colorDisplay(String displayText) {
super();
this.displayText = displayText;
foreground = null;
background = null;
}
// Set the foreground and background display
public void setForeColor(Color fgd) {
foreground = fgd;
}
public void setBackColor(Color bgd) {
background = bgd;
}
// The layout will call this to get the minimum size
// of the object. In this case we want it to be at
// least big enough to fit the display test...
public Dimension minimumSize() {
// Get the metrics of the current font...
FontMetrics fm = getFontMetrics(getFont());
return new Dimension(fm.stringWidth(displayText),
2 * fm.getHeight());
}
// Paint the colors and text...
public synchronized void paint(Graphics g) {
if ((foreground == null) || (background == null))
return;
// Set background...
Dimension dm = size();
g.setColor(background);
g.fillRect(0,0,dm.width,dm.height);
// Draw the string
g.setColor(foreground);
// Set dimensions. Move just from left...
FontMetrics fm = getFontMetrics(getFont());
int x = fm.charWidth('W');
// And center in height...
int y = fm.getHeight();
g.drawString(displayText,x,y);
}
}
// Class that creates a series of radio buttons
// for Colors to choose....
class ColoredCheckboxGroup extends CheckboxGroup {
// Array to hold checkboxes...
ColoredCheckbox c[] = new ColoredCheckbox[12];
// Constructor. Create the checkboxes with
// no default color chosen...
public ColoredCheckboxGroup(Panel p) {
// Call the default constructor...
super();
// Create the checkboxes and store references...
c[0] = new ColoredCheckbox(Color.black,"Black",this,false);
p.add(c[0]);
c[1] = new ColoredCheckbox(Color.cyan,"Cyan",this,false);
p.add(c[1]);
c[2] = new ColoredCheckbox(Color.blue,"Blue",this,false);
p.add(c[2]);
c[3] = new ColoredCheckbox(Color.darkGray,"Dark Gray",this,false);
p.add(c[3]);
c[4] = new ColoredCheckbox(Color.pink,"Pink",this,false);
p.add(c[4]);
c[5] = new ColoredCheckbox(Color.green,"Green",this,false);
p.add(c[5]);
c[6] = new ColoredCheckbox(Color.lightGray,"Light Gray",this,false);
p.add(c[6]);
c[7] = new ColoredCheckbox(Color.magenta,"Magenta",this,false);
p.add(c[7]);
c[8] = new ColoredCheckbox(Color.red,"Red",this,false);
p.add(c[8]);
c[9] = new ColoredCheckbox(Color.white,"White",this,false);
p.add(c[9]);
c[10] = new ColoredCheckbox(Color.orange,"Orange",this,false);
p.add(c[10]);
c[11] = new ColoredCheckbox(Color.yellow,"Yellow",this,false);
p.add(c[11]);
}
// Set the radio button of the checkbox that
// matches the color
public void setMatchingColor(Color match) {
for (int i = 0; i < c.length; ++i)
c[i].setIfColorMatches(match);
}
}
// Class for creating a checkbox associated
// with a given color...
class ColoredCheckbox extends Checkbox {
Color color; // The color of this checkbox...
// Constructor creates checkbox with specified color...
public ColoredCheckbox(Color color, String label,
CheckboxGroup grp, boolean set) {
// Call the default constructor...
super(label,grp,set);
this.color = color;
setBackground(color);
}
// Sets itself to true if it matches the color
public void setIfColorMatches(Color match) {
if (color == match)
setState(true);
else
setState(false);
}
// Return the color matching this box...
public Color getColor() {
return color;
}
}
===============================
/* ChooseFontDialog.java Author Casey Hopson
* Geist Software and Services, Inc.
*
* Permission to use, copy, modify, and distribute
* this software for NON_COMMERCIAL purposes and without
* fee is hereby granted provided that this copyright notice
* appears in all copies.
*
* The creators of this software make no representations or
* warranties about the suitability of the software, either
* express or implied. The creators shall not be liable for
* any damages suffered by licensee as a result of using,
* modifying or distributing this software or its derivatives.
*/
import java.awt.*;
import java.lang.*;
// Dialog box for choosing display colors...
public class ChooseFontDialog extends Dialog {
SpreadsheetFrame fr; // What to update...
SpreadsheetContainer s;
List choiceList; // List of color choices...
fontDisplay d; // This is the text display...
Choice choiceSize; // Size of font...
Checkbox checkItalics;
Checkbox checkBold;
Font currentFont; // Current font in sample...
Font defaultFont; // Store font dialog was created with...
// Construct dialog to allow color to be chosen...
public ChooseFontDialog(Frame parent,boolean modal) {
// Create dialog with title
super(parent,"Font Dialog",modal);
fr = (SpreadsheetFrame)parent;
defaultFont = getFont();
// Create the dialog components...
createComponents();
}
// Get the default font and set up display...
private void setDefaultFont() {
// Get the latest spreadsheet font...
currentFont = s.getFont();
// Get default list...
String s = currentFont.getName();
int index = findListString(choiceList,s);
if (index >= 0)
choiceList.select(index);
else
choiceList.select(0);
// Get default size
int sizeFont = currentFont.getSize();
index = findChoiceString(choiceSize,
String.valueOf(sizeFont));
if (index >= 0)
choiceSize.select(index);
else
choiceSize.select(0);
// Set the style displays...
int styleFont = currentFont.getStyle();
if ((styleFont & Font.BOLD) != 0)
checkBold.setState(true);
else
checkBold.setState(false);
if ((styleFont & Font.ITALIC) != 0)
checkItalics.setState(true);
else
checkItalics.setState(false);
// Set the canvas style...
d.setFont(currentFont);
}
// Wait for Cancel or OK buttons to be chosen...
public boolean handleEvent(Event e) {
switch(e.id) {
case Event.ACTION_EVENT:
// Kill the dialog...
if (e.arg.equals("Cancel")) {
dispose(); // Remove Dialog...
return true;
} // end if
// Update colors on the spreadsheet...
if (e.arg.equals("OK")) {
s.setFont(currentFont);
dispose();
return true;
} // end if
if (e.target instanceof Choice) {
paintSample();
return false;
} // end list if
if (e.target instanceof Checkbox) {
paintSample();
return false;
} // end list if
return false;
// User selected a listbox item...
case Event.LIST_SELECT:
// Set up caption colors and color choice highlight...
if (e.target instanceof List) {
paintSample();
return false;
} // end list if
return false;
default:
return false;
} // end switch
}
// The layout will call this to get the preferred size
// of the dialog. Make it big enough for the listbox text
// the checkboxes, canvas, and buttons...
public Dimension preferredSize() {
// Get the metrics of the current font...
FontMetrics fm = getFontMetrics(getFont());
int width = 3 * fm.stringWidth("Highlighted foreground");
int height = 14 * fm.getHeight();
return new Dimension(width,height);
}
// Create the main display panel...
private void createComponents() {
// Use gridbag constraints...
GridBagLayout g = new GridBagLayout();
setLayout(g);
GridBagConstraints gbc = new GridBagConstraints();
// Set the constraints for the top objects...
gbc.fill = GridBagConstraints.BOTH;
gbc.weightx = 1.0;
gbc.weighty = 1.0;
gbc.gridheight = 10;
// Add the listbox of choices...
// Get the selection from the toolkit...
choiceList = new List();
String fontList[] = Toolkit.getDefaultToolkit().getFontList();
for (int i = 0; i < fontList.length; ++i)
choiceList.addItem(fontList[i]);
g.setConstraints(choiceList,gbc);
add(choiceList);
// Set the default values...
gbc.weighty = 0.0;
gbc.weightx = 1.0;
gbc.gridheight = 1;
gbc.gridwidth = GridBagConstraints.REMAINDER;
// Create a label for display...
Label l = new Label("Size:");
// Add to grid bag...
g.setConstraints(l,gbc);
add(l);
// Create the choice box...
choiceSize = new Choice();
choiceSize.addItem("8");
choiceSize.addItem("10");
choiceSize.addItem("12");
choiceSize.addItem("14");
choiceSize.addItem("16");
choiceSize.addItem("20");
// Add to grid bag...
g.setConstraints(choiceSize,gbc);
add(choiceSize);
// Add Italics...
checkItalics = new Checkbox("Italics");
g.setConstraints(checkItalics,gbc);
add(checkItalics);
// Add Bold...
checkBold = new Checkbox("Bold");
g.setConstraints(checkBold,gbc);
add(checkBold);
// Display the color chosen...
d = new fontDisplay("Sample Text");
// Add to grid bag...
g.setConstraints(d,gbc);
add(d);
// Two buttons: "OK" and "Cancel"
Panel p = new Panel();
p.add(new Button("OK"));
p.add(new Button("Cancel"));
// Add to grid bag...
gbc.gridwidth = GridBagConstraints.REMAINDER;
g.setConstraints(p,gbc);
add(p);
}
// Setup defaults upon showing...
public synchronized void show() {
super.show(); // Call the default constructor...
// Get the spreadsheet container...
s = fr.getSpreadsheetContainer();
// Set the font dialog started off with...
setFont(defaultFont);
// Set up defaults...
setDefaultFont();
pack(); // Compact...
// Resize to fit everything...
resize(preferredSize());
}
// Repaint the sample canvas...
private synchronized void paintSample() {
// Get all the users selections....
String fontName = choiceList.getSelectedItem();
String fontSize = choiceSize.getSelectedItem();
int fontStyle = Font.PLAIN;
if (checkItalics.getState())
fontStyle += Font.ITALIC;
if (checkBold.getState())
fontStyle += Font.BOLD;
// Set the new font on the canvas...
currentFont = new Font(fontName,fontStyle,
Integer.parseInt(fontSize));
d.setFont(currentFont);
d.repaint();
}
// Return index of string in list...
// -1 means not found
public int findListString(List l,String s) {
for (int i = 0; i < l.countItems(); ++i) {
if (s.equals(l.getItem(i)) )
return i;
}
return -1;
}
// Return index of string in choice...
// -1 means not found
public int findChoiceString(Choice c,String s) {
for (int i = 0; i < c.countItems(); ++i) {
if (s.equals(c.getItem(i)) )
return i;
}
return -1;
}
}
// A small class that illustrates the
// current highlight and background
class fontDisplay extends Canvas {
String displayText;
// Construct the display by storing the
// text to be displayed...
public fontDisplay(String displayText) {
super();
this.displayText = displayText;
}
// The layout will call this to get the minimum size
// of the object. In this case we want it to be at
// least big enough to fit the display test...
public Dimension minimumSize() {
// Get the metrics of the current font...
FontMetrics fm = getFontMetrics(getFont());
return new Dimension(fm.stringWidth(displayText),
4 * fm.getHeight());
}
// Paint the colors and text...
public synchronized void paint(Graphics g) {
// Set background...
Dimension dm = size();
g.setColor(Color.white);
g.fillRect(0,0,dm.width,dm.height);
// Draw the string
g.setColor(Color.black);
// Set dimensions. Move just from left...
FontMetrics fm = getFontMetrics(getFont());
int x = fm.charWidth('I');
// And center in height...
int y = fm.getHeight();
g.drawString(displayText,x,y);
}
}
================================
/* FormulaParser.java Author Casey Hopson
* Geist Software and Services, Inc.
*
* Permission to use, copy, modify, and distribute
* this software for NON_COMMERCIAL purposes and without
* fee is hereby granted provided that this copyright notice
* appears in all copies.
*
* The creators of this software make no representations or
* warranties about the suitability of the software, either
* express or implied. The creators shall not be liable for
* any damages suffered by licensee as a result of using,
* modifying or distributing this software or its derivatives.
*/
// This file holds the class that is used for parsing
// Cell formulas...
import java.lang.*;
// This class is used to parse a single formula at a time.
// It uses internal hints to keep track of the current position
// in the name of performance. Misuse of this parser could result
// in unexpected results.
public class FormulaParser {
// Set up codes for types of formulas
public final static int EMPTY = 0;
public final static int LITERAL = 1;
public final static int FORMULA = 2;
// Here are the formula operations...
final static String sSUM = "SUM";
final static String sADD = "ADD";
final static String sSUB = "SUB";
final static String sMULT = "MULT";
final static String sDIV= "DIV";
public final static int INVALID_OPERATION = 0;
public final static int SUM = 1;
public final static int ADD = 2;
public final static int SUB = 3;
public final static int MULT = 4;
public final static int DIV = 5;
// Internal fields...
String formula;
int index; // Last char looked at...
int lParen; // First lParen in the expression...
int operation; // The current operations
// Constructors...
public FormulaParser() {
formula = null;
}
public FormulaParser(String formula) {
setFormula(formula);
}
// Set a new formula to use...
public void setFormula(String formula) {
// Remove white spaces...
this.formula = formula.trim();
index = 0;
}
// Figure out what type of Formula this is...
public int getType() {
// Return empty if there is nothing there...
if (formula.length() == 0)
return EMPTY;
// See if it is a formula by looking for lparen...
if ((lParen = formula.indexOf( '(' ) ) > 0) {
return FORMULA;
} // end if
return LITERAL;
}
// Find the type of operation being performed...
public int getOperation() throws FormulaParserException {
String op = formula.substring(0,lParen);
if (op.compareTo(sSUM) == 0) {
operation = SUM;
return operation;
} // end if
if (op.compareTo(sADD) == 0) {
operation = ADD;
return operation;
} // end if
if (op.compareTo(sSUB) == 0) {
operation = SUB;
return operation;
} // end if
if (op.compareTo(sMULT) == 0) {
operation = MULT;
return operation;
} // end if
if (op.compareTo(sDIV) == 0) {
operation = DIV;
return operation;
} // end if
operation = INVALID_OPERATION;
throw new FormulaParserException();
}
// Get arguments for a simple numeric operation...
public void getOpArgs(ArgValue arg1,ArgValue arg2) throws FormulaParserException {
int sep, rParen;
// Find where separator is...
if ((sep = formula.indexOf(',',lParen)) < 0)
throw new FormulaParserException();
// Find the rparen
if ((rParen = formula.indexOf(')',sep)) < 0)
throw new FormulaParserException();
// See what between these...
try {
setArg(arg1,formula.substring(lParen + 1,sep).trim());
setArg(arg2,formula.substring(sep + 1,rParen).trim());
}
catch (FormulaParserException e){
throw e;
}
}
// Set the argument values for part of a formula
void setArg(ArgValue arg,String s) throws FormulaParserException {
// If first char is a digit then it needs to be a literal...
if (Character.isDigit(s.charAt(0)) ) {
// Convert to a number!
try {
Double d = new Double(s); // Parse the string...
arg.setLiteral(d.doubleValue()); // Get the double value..
return;
}
// Some kind of invalid string...
catch(NumberFormatException e) {
throw new FormulaParserException();
}
} // end # if
else {
// Convert the alpha to the row...
try {
int row = ((int)(s.charAt(0))) - 'A';
Integer iCol = new Integer(s.substring(1));
int col = iCol.intValue();
arg.setCell(row,col);
}
// Some kind of invalid string...
catch(NumberFormatException e) {
throw new FormulaParserException();
}
} // end else
}
// Get a literal value...
public double getLiteral() throws FormulaParserException {
try {
Double d = new Double(formula); // Parse the string...
double dbl = d.doubleValue(); // Get the double value...
return dbl;
}
// Some kind of invalid string...
catch(NumberFormatException e) {
throw new FormulaParserException();
}
}
}
====================================
/* FormulaParserException.java Author Casey Hopson
* Geist Software and Services, Inc.
*
* Permission to use, copy, modify, and distribute
* this software for NON_COMMERCIAL purposes and without
* fee is hereby granted provided that this copyright notice
* appears in all copies.
*
* The creators of this software make no representations or
* warranties about the suitability of the software, either
* express or implied. The creators shall not be liable for
* any damages suffered by licensee as a result of using,
* modifying or distributing this software or its derivatives.
*/
import java.lang.*;
// This class is an Exception thrown when a
// formula is an invalid format...
public class FormulaParserException extends IllegalArgumentException { }
===================================
/* GraphData.java Author Casey Hopson
* Geist Software and Services, Inc.
*
* Permission to use, copy, modify, and distribute
* this software for NON_COMMERCIAL purposes and without
* fee is hereby granted provided that this copyright notice
* appears in all copies.
*
* The creators of this software make no representations or
* warranties about the suitability of the software, either
* express or implied. The creators shall not be liable for
* any damages suffered by licensee as a result of using,
* modifying or distributing this software or its derivatives.
*/
import java.lang.*;
// This class encapsulates the data that is used to
// create graphs...
// Assumes data and headings arrays are the same size...
public class GraphData {
double data[]; // The data to be plotted
String headings[]; // The headings associated with the data...
// Constructor stores data created elsewhere...
public GraphData(double data[],String headings[]) {
this.data = data;
this.headings = headings;
}
// Accessor functions...
public int size() {
return data.length;
}
// Return double value at an index...
public double getData(int index) {
return data[index];
}
// Return heading at an index...
public String getHeading(int index) {
return headings[index];
}
}
=====================================
/* GraphDialog.java Author Casey Hopson
* Geist Software and Services, Inc.
*
* Permission to use, copy, modify, and distribute
* this software for NON_COMMERCIAL purposes and without
* fee is hereby granted provided that this copyright notice
* appears in all copies.
*
* The creators of this software make no representations or
* warranties about the suitability of the software, either
* express or implied. The creators shall not be liable for
* any damages suffered by licensee as a result of using,
* modifying or distributing this software or its derivatives.
*/
import java.awt.*;
import java.lang.*;
// Dialog box for choosing display colors...
public class GraphDialog extends Dialog {
// Types of graphs...
static final int LINE_GRAPH = 0;
static final int BAR_GRAPH = 1;
GraphCanvas gc;
// Construct dialog that shows a graph of data...
public GraphDialog(Frame parent,boolean modal) {
// Create dialog with title
super(parent,"Display Graph",modal);
setLayout(new BorderLayout());
// Create Graphic display object and Button
gc = new GraphCanvas();
add("Center",gc);
add("South",new Button("Done"));
// Pack and set to be most of the screen...
pack();
// Get the screen dimensions...
Dimension screen = Toolkit.getDefaultToolkit().getScreenSize();
// Get the font and use to calculate some margins...
FontMetrics fm = Toolkit.getDefaultToolkit().getFontMetrics(getFont());
resize(screen.width,screen.height - (4 * fm.getHeight()) );
}
// Wait for Cancel or OK buttons to be chosen...
public boolean handleEvent(Event e) {
switch(e.id) {
case Event.ACTION_EVENT:
// Kill the dialog...
if (e.arg.equals("Done")) {
dispose(); // Remove Dialog...
return true;
} // end if
return false;
default:
return false;
} // end switch
}
// Setup defaults upon showing...
public synchronized void show(GraphData gphData,int graphMode) {
// Set up the appropriate graph...
gc.prepareNewGraph(gphData,graphMode);
// Show the graph...
super.show();
}
}
// This paints a graph on a canvas...
class GraphCanvas extends Canvas {
// Types of graphs...
static final int LINE_GRAPH = 0;
static final int BAR_GRAPH = 1;
int graphMode;
Color randomColors[];
// This is the data for the display..
GraphData gd;
// Maximum scale of graph...
int maxValue;
// Constructor just inits data...
public GraphCanvas() {
gd = null;
// Store the random colors...
randomColors = new Color[6];
randomColors[0] = Color.yellow;
randomColors[1] = Color.red;
randomColors[2] = Color.green;
randomColors[3] = Color.magenta;
randomColors[4] = Color.cyan;
randomColors[5] = Color.blue;
}
// Set up graphics display...
void prepareNewGraph(GraphData gphData,int graphMode) {
// Store the data and string values...
gd = gphData;
this.graphMode = graphMode;
// First calculate maximum value of graph...
maxValue = calculateMaxValue();
}
// Calculate the maximum value of the graph...
int calculateMaxValue() {
double maximum = 0.0;
double data;
int temp,roundMax;
// First get maximum figure...
int length = gd.size();
for (int i = 0; i < length; ++i) {
data = gd.getData(i);
if (data > maximum)
maximum = data;
} // end for
// Now round it up to nearest power of 10
roundMax = 1;
for (temp = (int)maximum;temp > 0; temp /= 10)
roundMax *= 10;
return roundMax;
}
// Draw the graph...
public synchronized void paint (Graphics g) {
if (gd == null)
return;
Dimension dm = size();
// Calculate margins...
int height = g.getFontMetrics().getHeight();
int ymargin = 3 * height;
int xmargin = g.getFontMetrics().stringWidth("1112345.67");
int length = gd.size();
// Select bottom-left origin
Point origin = new Point(xmargin,dm.height - ymargin);
// Draw X-Axis line
int endx = dm.width - xmargin;
g.drawLine(origin.x,origin.y,endx,origin.y);
// Draw Y-Axis line
g.drawLine(origin.x,ymargin,origin.x,origin.y);
// Calculate how headers are spread out...
int yIncrement = (origin.y - ymargin)/10;
int xIncrement = (endx - origin.x) / (length + 1);
// Draw horizontal axis headers
int i,x;
int yMarkStart = origin.y + height;
int yTextStart = yMarkStart + height;
for (i = 1; i < (length + 1); ++i) {
// Draw marker...
x = origin.x + (xIncrement * i);
g.drawLine(x,yMarkStart,x,origin.y);
// Print value header...
g.drawString(gd.getHeading(i - 1),x,yTextStart);
}
// Draw vertical axis headers...
int y;
int inset = g.getFontMetrics().charWidth('W');
int xMarkStart = origin.x - inset;
int xTextStart = inset;
int dataIncrement = maxValue / 10;
String yHeader;
for (i = 0; i <= 10; ++i) {
// Draw marker...
y = origin.y - (i * yIncrement);
g.drawLine(xMarkStart,y,origin.x,y);
// Print increment header...
yHeader = String.valueOf(dataIncrement * i);
g.drawString(yHeader,xTextStart,y);
}
// Call Graphic specific drawing..
int vertLength = origin.y - ymargin;
double dbLen = (double)randomColors.length;
int index;
int rectOffset = xIncrement / 2; // For bar graphs...
Point lastPt = null;
for (i = 1; i < (length + 1); ++i) {
// Plot points, connecting points with lines...
x = origin.x + (xIncrement * i);
y = origin.y - (int)((gd.getData(i - 1)/maxValue) * vertLength);
// Randomize colors...
index = (int)(dbLen * Math.random());
g.setColor(randomColors[index]);
// If line graph draw connecting lines...
if (graphMode == LINE_GRAPH) {
if (lastPt != null)
g.drawLine(lastPt.x,lastPt.y,x,y);
lastPt = new Point(x,y);
}
// Otherwise, bar graph draw rectangle...
else {
g.fillRect(x - rectOffset,y,xIncrement,origin.y - y);
}
} // end for
}
}
========================
SPREADSHEET.HTML
<title>Spreadsheet Applet A</title>
<hr>
<applet code="SpreadsheetApplet" width=300 height=20>
<PARAM NAME=filesEnabled VALUE="true">
</applet>
<hr>
<a href="SpreadsheetApplet.java">The source.</a>
==========================================================
/* SpreadsheetApplet.java Author Casey Hopson
* Geist Software and Services, Inc.
*
* Permission to use, copy, modify, and distribute
* this software for NON_COMMERCIAL purposes and without
* fee is hereby granted provided that this copyright notice
* appears in all copies.
*
* The creators of this software make no representations or
* warranties about the suitability of the software, either
* express or implied. The creators shall not be liable for
* any damages suffered by licensee as a result of using,
* modifying or distributing this software or its derivatives.
*/
// This file describes the applet class that manages the
// spreadsheet program.
import java.awt.*;
import java.io.*;
import java.lang.*;
import java.applet.*;
// This applet kicks off the SpreadsheetFrame
// which manages the spreadsheet program.
public class SpreadsheetApplet extends Applet {
SpreadsheetFrame fr;
public void init() {
int rows = 25; // Default sizes...
int cols = 40;
// Get parameter to see if we should enable
// local file enabling...
boolean enableFiles = false;
try {
String s = getParameter("filesEnabled");
if (s.equals("true"))
enableFiles = true;
}
// If error, use false default...
catch (Exception e) { }
// Create the spreadsheet frame
fr = new SpreadsheetFrame(this,rows,cols,enableFiles);
}
// If returning to screen for first time show frame...
public void start() {
// Redisplay the applet...
try {
fr.show();
}
// Handle any problem...
catch(Exception e) { }
}
// Hide the frame upon leaving...
public void stop() {
// Handle where it may have been disposed...
try {
fr.hide();
}
// Handle any problem...
catch(Exception e) { }
}
}
// This is the frame that controls that user interaction
// with the applet. It creates the initial spreadsheet data
// and visual container, along with the input field for
// changing values of a cell, the scrollbars, and the menus
class SpreadsheetFrame extends Frame {
CellContainer c; // The actual spreadsheet data...
SpreadsheetContainer s; // The spreadsheet view
Scrollbar hScroll; // The scrollbars...
Scrollbar vScroll;
GridBagLayout g; // Layout for Frame
MenuBar mbar; // The frames menu...
TextField t; // The text field for the spreadsheet...
SpreadsheetCell currHighlight; // The currently highlighted cell...
Applet appl; // The applet...
int numRows; // Keep the initial parameters...
int numCols;
ChooseColorDialog colorDialog; // Color Dialog...
ChooseFontDialog fontDialog; // Font Dialog...
GraphDialog graphDialog; // For displaying graphs...
FileDialog openFileDialog; // File Open Dialog...
FileDialog saveFileDialog; // File Save Dialog...
// Don't use File Dialogs if this is a Network
// version of the spreadsheet...
boolean enableFiles = false;
// The constructor for the spreadsheet frame takes the
// values of the size of the Spreadsheet...
public SpreadsheetFrame(Applet a,int rows, int cols,
boolean enableFiles) {
super("Spreadsheet Applet");
// Set the initial size and layouts...
resize(300,200);
g = new GridBagLayout();
setLayout(g);
appl = a; // Store the applet...
this.enableFiles = enableFiles;
numRows = rows;
numCols = cols;
// Create the new container based on the applet parameters...
try {
c = new CellContainer(rows,cols);
}
catch (IllegalArgumentException e) {
System.out.println("Invalid Spreadsheet parameters");
dispose();
}
addTestData();
// Create display components...
addDisplayComponents();
// Add the menu choices to the frames
addMenuItems();
// Create the dialogs...
colorDialog = new ChooseColorDialog(this,true);
fontDialog = new ChooseFontDialog(this,true);
openFileDialog = new FileDialog(this,"Open File",
FileDialog.LOAD);
saveFileDialog = new FileDialog(this,"Save File",
FileDialog.SAVE);
graphDialog = new GraphDialog(this,true);
// Pack before display...
pack();
resize(300,200); // Then reset to default value...
show();
}
// Handle system and user events...
public boolean handleEvent(Event evt) {
switch(evt.id) {
case Event.WINDOW_DESTROY: {
dispose(); // Kill the frame...
return true;
}
// This can be handled
case Event.ACTION_EVENT: {
String menu_name = evt.arg.toString();
if (evt.target instanceof MenuItem) {
// Exit...
if(menu_name.equals("Quit"))
dispose(); // Kill the frame...
// New Spreadsheet...
if(menu_name.equals("New"))
newSpreadsheet();
// Open a Spreadsheet...
if(menu_name.equals("Open"))
openSpreadsheetDialog();
// Save a Spreadsheet...
if(menu_name.equals("Save"))
saveSpreadsheetDialog();
// Set colors...
if(menu_name.equals("Colors..."))
colorDialog.show();
// Set fonts...
if(menu_name.equals("Fonts..."))
fontDialog.show();
// Show line graph...
if((menu_name.equals("Line Graph...")) ||
(menu_name.equals("Bar Graph...")) )
launchGraphicsDialog(menu_name);
} // end if
// Handle entry of new text data entered...
if (evt.target instanceof TextField) {
validateNewFormula();
return true;
} // end if
// Notification of a new cell highlighted
if (evt.target instanceof SpreadsheetContainer) {
changeInputFormula((SpreadsheetCell)evt.arg);
return true;
}
return false;
}
case Event.SCROLL_LINE_UP:
case Event.SCROLL_ABSOLUTE:
case Event.SCROLL_LINE_DOWN:
case Event.SCROLL_PAGE_UP:
case Event.SCROLL_PAGE_DOWN:
if (evt.target instanceof Scrollbar) {
scrollbarAction((Scrollbar)evt.target);
} // end if
return true;
default:
return false;
}
}
// Add the menu choices to the frames
void addMenuItems() {
mbar = new MenuBar();
// Add the File menu items......
Menu m = new Menu("File");
m.add(new MenuItem("New"));
if (enableFiles) {
m.add(new MenuItem("Open"));
m.add(new MenuItem("Save"));
}
m.addSeparator();
m.add(new MenuItem("Quit"));
mbar.add(m);
// Add the Graph displays......
m = new Menu("Graphs");
m.add(new MenuItem("Line Graph..."));
m.add(new MenuItem("Bar Graph..."));
mbar.add(m);
// Add the Options menu items......
m = new Menu("Options");
m.add(new MenuItem("Colors..."));
m.add(new MenuItem("Fonts..."));
mbar.add(m);
setMenuBar(mbar);
}
// Add the spreadsheet, input field and scrollbars
// to display...
void addDisplayComponents() {
GridBagConstraints gbc = new GridBagConstraints();
// Create an input field across the top...
gbc.fill = GridBagConstraints.BOTH;
gbc.weightx = 1.0;
gbc.gridwidth = GridBagConstraints.REMAINDER;
t = new TextField();
g.setConstraints(t,gbc);
add(t);
// Create the spreadsheet display...
gbc.fill = GridBagConstraints.BOTH;
gbc.weightx = 1.0;
gbc.weighty = 1.0;
gbc.gridwidth = GridBagConstraints.RELATIVE;
gbc.gridheight = 10;
s = new SpreadsheetContainer(c);
g.setConstraints(s,gbc);
add(s);
// Add vertical scrollbar...
gbc.gridwidth = GridBagConstraints.REMAINDER;
vScroll = new Scrollbar(Scrollbar.VERTICAL,1,1,1,numRows);
g.setConstraints(vScroll,gbc);
add(vScroll);
// Add horizontal scrollbar...
hScroll = new Scrollbar(Scrollbar.HORIZONTAL,1,1,1,numCols);
gbc.weightx = 1.0;
gbc.weighty = 1.0;
gbc.gridwidth = GridBagConstraints.REMAINDER;
gbc.gridheight = 1;
g.setConstraints(hScroll,gbc);
add(hScroll);
// Set initial formula for text field...
changeInputFormula(s.getHighlight());
}
// Change the formula of the input field to that of
// the Object argument, which is a spreadsheet cell...
void changeInputFormula(SpreadsheetCell sc) {
// Set the text box with the formula...
if (sc != null)
t.setText(sc.getString());
else
t.setText("");
// Store the currently highlighted cell...
currHighlight = sc;
}
// A text field formula has been entered...
// Validate it and update spreadsheet...
// Update text field where necessary...
void validateNewFormula() {
// Put up wait icon for calculations...
int oldCursor = getCursorType();
setCursor(WAIT_CURSOR);
try {
// Replace the formula. If no problem then
// spreadsheet will be recalculated...
s.replaceFormula(currHighlight, t.getText());
appl.getAppletContext().showStatus("Formula accepted.");
}
catch (Exception e) { // Handle illegal exception...
// Let browser status bar know about error...
// Get the status bar from the AppletContext...
appl.getAppletContext().showStatus("Illegal Formula syntax: Use SUM,ADD,SUB,MULT,DIV");
}
// Always place the converted formula in the text field...
changeInputFormula(s.getHighlight());
setCursor(oldCursor);
}
// Reload spreadsheet with blank data...
void newSpreadsheet() {
// Create the new container based on the applet parameters...
try {
c = new CellContainer(numRows,numCols);
s.newCellContainer(c);
// Set initial formula for text field...
changeInputFormula(s.getHighlight());
// Reset scrollbars...
vScroll.setValue(vScroll.getMinimum());
hScroll.setValue(hScroll.getMinimum());
}
catch (IllegalArgumentException e) {
System.out.println("Invalid Spreadsheet parameters");
dispose();
}
}
// Return a reference to the spreadsheet container...
public SpreadsheetContainer getSpreadsheetContainer() {
return s;
}
// Call Open Dialog, and load a file if a choice
// was made...
void openSpreadsheetDialog() {
// Show the dialog
openFileDialog.show();
// If a file was chosen then open it...
if (openFileDialog.getFile() != null) {
String filename,fullname;
filename = openFileDialog.getFile();
// Hack for Win 95 Java bug...
int index = filename.indexOf(".*.*");
if (index >= 0)
filename = filename.substring(0,index);
// Get the name of the file to save...
if (openFileDialog.getDirectory() != null)
fullname = openFileDialog.getDirectory() + filename;
else
fullname = filename;
// Open the file into new Cell container...
int oldCursor = getCursorType(); // Put up an hourglass...
setCursor(WAIT_CURSOR);
try {
c = new CellContainer(fullname);
c.recalculateAll(); // Recalculate the values...
// Load it into the spreadsheet...
s.newCellContainer(c);
// Set initial formula for text field...
changeInputFormula(s.getHighlight());
// Reset scrollbars...
vScroll.setValue(vScroll.getMinimum());
hScroll.setValue(hScroll.getMinimum());
appl.getAppletContext().showStatus("Opened file " + filename);
}
// Handle error saving file...
// Print out reason for failure...
catch (IOException e) {
appl.getAppletContext().showStatus("Unable to open: "
+ e.getMessage());
}
setCursor(oldCursor);
} // end if
}
// Call Save Dialog, and load a file if a choice
// was made...
void saveSpreadsheetDialog() {
saveFileDialog.show();
// If a file was chosen then save it...
if (saveFileDialog.getFile() != null) {
String filename,fullname;
filename = saveFileDialog.getFile();
// Hack for Win 95 Java bug...
int index = filename.indexOf(".*.*");
if (index >= 0)
filename = filename.substring(0,index);
// Get the name of the file to save...
if (saveFileDialog.getDirectory() != null)
fullname = saveFileDialog.getDirectory() + filename;
else
fullname = filename;
// Save the file!
int oldCursor = getCursorType(); // Put up an hourglass...
setCursor(WAIT_CURSOR);
try {
c.saveFile(fullname);
}
// Handle error saving file...
catch (IOException e) {
appl.getAppletContext().showStatus("Unable to save file " + filename);
}
setCursor(oldCursor); // Back to arrow..
} // end if
}
// Launch the graphics dialog. Load the double
// and headers
public void launchGraphicsDialog(String graphType) {
// Get the graphics data to be displayed...
try {
GraphData gd = s.getGraphData();
// Show it if there is something...
if (graphType.equals("Line Graph...") )
graphDialog.show(gd,graphDialog.LINE_GRAPH);
else
graphDialog.show(gd,graphDialog.BAR_GRAPH);
}
// Catch error if nothing marked...
catch (IllegalArgumentException e) {
appl.getAppletContext().showStatus(e.getMessage());
}
}
// Handle scroll bar actions...
void scrollbarAction(Scrollbar sb) {
if (sb.getOrientation() == Scrollbar.VERTICAL)
s.setNewTop(sb.getValue());
else
s.setNewLeft(sb.getValue());
}
void addTestData() {
c.setCellFormula("1",0,0);
c.setCellFormula("2",0,1);
c.setCellFormula("3",0,2);
c.setCellFormula("4",0,3);
c.setCellFormula("SUM(A0,A3)",0,4); // Should be 10
c.recalculateAll();
}
}
========================================
/* SpreadsheetCell.java Author Casey Hopson
* Geist Software and Services, Inc.
*
* Permission to use, copy, modify, and distribute
* this software for NON_COMMERCIAL purposes and without
* fee is hereby granted provided that this copyright notice
* appears in all copies.
*
* The creators of this software make no representations or
* warranties about the suitability of the software, either
* express or implied. The creators shall not be liable for
* any damages suffered by licensee as a result of using,
* modifying or distributing this software or its derivatives.
*/
import java.awt.*;
import java.lang.*;
// This class ties the contents of an individual
// SpreadsheetCell to a single data Cell.
// The evaluated contents of
// that cell are returned to the SpreadsheetContainer...
public class SpreadsheetCell extends Canvas {
Cell c; // The cell this is tied to...
boolean literal; // If set to true, automatically paint what's in cell string...
Color fillColor;
Color textColor;
// Store positions of last repaint...
boolean validCoor = false; // True if we have valid coordinates...
int lastX,lastY,lastWidth,lastHeight;
public SpreadsheetCell(Cell c,boolean literal) {
super();
this.c = c;
this.literal = literal;
// Set the color defaults...
fillColor = Color.white;
textColor = Color.black;
}
// Set the fill color
public void setFillColor(Color clr) {
fillColor = clr;
}
// Set the text color
public void setTextColor(Color clr) {
textColor = clr;
}
// Return the reference to the cell...
public Cell getCell() {
return c;
}
// Set the cell string...
public void setString(String s) {
c.setCellString(s);
}
// Get the current string value in the cell...
public String getString() {
return c.getCellString();
}
// Get evaluated value
public double getEvalValue() {
return c.getEvalValue();
}
// This will return the text to the current evaluated contents
// of the cell...
public synchronized void paint(Graphics g,int x,int y,int width,int height) {
String s = c.getCellString();
String textPaint;
// If this is a literal value then print what it has...
if (literal == true)
textPaint = s;
else {
// Otherwise, display formula only if cell is not empty...
if (s.compareTo("") == 0)
textPaint = s;
else // Otherwise show evaluate value...
textPaint = String.valueOf(c.getEvalValue()) ;
} // end else
// Set up drawing rectangle...
g.setColor(Color.blue);
g.drawRect(x,y,width,height);
g.setColor(fillColor);
g.fillRect(x + 1,y + 1,width - 2,height - 2);
// Clip the text if necessary...
int textWidth;
int len = textPaint.length();
int effWidth = width - 4;
// Loop until text is small enough to fit...
while (len > 0) {
textWidth = g.getFontMetrics().stringWidth(textPaint);
if (textWidth < effWidth)
break;
--len;
textPaint = textPaint.substring(0,len);
} // end while
// Draw the string
g.setColor(textColor);
g.drawString(textPaint,x + 4,y + (height - 2));
// Store the coordinates...
validCoor = true;
lastX = x;
lastY = y;
lastWidth = width;
lastHeight = height;
}
// Return the literal value...
public boolean getLiteral() {
return literal;
}
// Get last coordinates painted...
public Rectangle getLastCoordinates() {
// If not valid yet return null
if (validCoor == false)
return null;
// Otherwise return a rectangle with the values...
return new Rectangle(lastX,lastY,lastWidth,lastHeight);
}
}
=============================================
/* SpreadsheetContainer.java Author Casey Hopson
* Geist Software and Services, Inc.
*
* Permission to use, copy, modify, and distribute
* this software for NON_COMMERCIAL purposes and without
* fee is hereby granted provided that this copyright notice
* appears in all copies.
*
* The creators of this software make no representations or
* warranties about the suitability of the software, either
* express or implied. The creators shall not be liable for
* any damages suffered by licensee as a result of using,
* modifying or distributing this software or its derivatives.
*/
import java.awt.*;
import java.lang.*;
// This class contains the cells that make up a spreadsheet...
public class SpreadsheetContainer extends Canvas {
// The actual spreadsheet data...
CellContainer c;
int numRows;
int numColumns;
SpreadsheetCell matrix[];
SpreadsheetCell emptyCell; // Empty cell for repainting blank areas...
// Graphic elements set in the paint routine...
int cellWidth;
int cellHeight;
// Keep track of what is highlighted...
SpreadsheetCell newHighlight;
SpreadsheetCell oldHighlight;
// Display colors
Color normalForeColor = Color.black;
Color normalBackColor = Color.white;
Color highlightedForeColor = Color.white;
Color highlightedBackColor = Color.red;
Color markedForeColor = Color.white;
Color markedBackColor = Color.blue;
// Keep track of scrolling positions...
int topCell; // Top cell displayed...
int leftCell; // Leftmost cell displayed...
// Use to keep track of paint data in test calculations...
int paintIndex = 0;
int paintX = 0;
int paintY = 0;
// More variables for temp storage...
int tempRow;
int tempCol;
// Construct container. Create internal paint matrix tied to
// the data container...
public SpreadsheetContainer(CellContainer ctnr) {
super();
// Load the container and set up the display...
loadContainer(ctnr);
}
// Take a cell container and load set the spreadsheet
// to use it. Put the highlight in the first cell...
void loadContainer(CellContainer ctnr) {
c = ctnr; // Store the CellContainer...
// Get size of spreadsheet...
numRows = c.getNumRows() + 1;
numColumns = c.getNumColumns() + 1;
// Create the SpreadsheetCell matrix...
matrix = new SpreadsheetCell[numRows * numColumns];
// Add the cells to the grid...
int i,j,index;
char ch;
// Add the column labels across the top...
for (j = 0; j < numColumns; ++j) {
// Create a literal cell for each column...
matrix[j] = new SpreadsheetCell(new Cell(),true);
// Set the cell contents and color...
if (j > 0)
matrix[j].setString(String.valueOf((j - 1)) );
matrix[j].setFillColor(Color.lightGray);
matrix[j].setTextColor(Color.blue);
} // end for
// Create the individual rows...
for (i = 1; i < numRows; ++i) {
// Set up the row header...
index = (i * (numColumns));
matrix[index] = new SpreadsheetCell(new Cell(),true);
ch = (char)('A' + (i - 1));
matrix[index].setString(String.valueOf(ch) );
matrix[index].setFillColor(Color.lightGray);
matrix[index].setTextColor(Color.blue);
// Now set the container cells...
for (j = 1; j < numColumns; ++j) {
index = (i * (numColumns)) + j;
matrix[index] = new SpreadsheetCell(c.getCell(i - 1,j - 1),false);
// Set the colors...
matrix[index].setFillColor(normalBackColor);
matrix[index].setTextColor(normalForeColor);
} // end inner for...
} // end outer for
// Create empty cell for painting blank areas...
emptyCell = new SpreadsheetCell(new Cell(),true);
emptyCell.setFillColor(Color.lightGray);
emptyCell.setTextColor(Color.blue);
// Marking is initially off...
setupMarking();
// Set scroll positions
topCell = 1;
leftCell = 1;
// Highlight the upper left cell...
index = getIndex(1,1);
newHighlight = matrix[index];
oldHighlight = newHighlight;
setCellHighlight(newHighlight,true);
}
// Attach a new container to the spreadsheet...
public void newCellContainer(CellContainer ctnr) {
// Load the container and set up the display...
loadContainer(ctnr);
repaint();
}
// Return the currently highlighted row...
public SpreadsheetCell getHighlight() {
return newHighlight;
}
// Get the index into the matrix for a row or column...
int getIndex(int row, int col) {
return ((row * numColumns) + col);
}
// Handle mouse clicks...
void setMouseHighlight(int x, int y) {
SpreadsheetCell tempHighlight;
// First figure out what cell is at those coordinates...
tempHighlight = calculatePaint(null,false,x,y);
// Make it the new highlight if it is not a border element...
if ((tempHighlight != null) && (tempHighlight.getLiteral() == false) ) {
newHighlight = tempHighlight;
// Turn off old highlight...
if ((oldHighlight != null) && (oldHighlight != newHighlight))
setCellHighlight(oldHighlight,false);
// Set new highlight...
setCellHighlight(newHighlight,true);
oldHighlight = newHighlight;
// Notify parent of change...
notifyParentOfHighlight(newHighlight);
}
}
// Highlight a cell
// If boolean is on then highlight, else set to normal...
void setCellHighlight(SpreadsheetCell sc,boolean on) {
if (on == true) { // Highlight it!
sc.setFillColor(highlightedBackColor);
sc.setTextColor(highlightedForeColor);
} // end if
else { // Set to normal...
sc.setFillColor(normalBackColor);
sc.setTextColor(normalForeColor);
} // end else...
// Force the cell to repaint...
// See if we can repaint just what is needed...
Rectangle r = sc.getLastCoordinates();
if (r != null)
repaint(r.x,r.y,r.width,r.height);
else
repaint();
}
// Handle scrolling by setting new top...
public void setNewTop(int newTop) {
// Set top taking into account headings and constraints...
if (newTop < numRows)
topCell = newTop;
else
topCell = numRows - 1;
resetMarking();
repaint();
}
// Set new leftmost column...
public void setNewLeft(int newLeft) {
// Set new left taking into account headings and constraints...
if (newLeft < numColumns)
leftCell = newLeft;
else
leftCell = numColumns - 1;
resetMarking();
repaint();
}
// Update message sent when repainting is needed...
// Prevent paint from getting cleared out...
public void update(Graphics g) {
paint(g);
}
// Draw the displayable spreadsheet contents...
public synchronized void paint (Graphics g) {
// Go through the calculations of the paint while painting...
calculatePaint(g,true,0,0);
}
// This goes through the motions of calculating what is on the
// screen and either calculates coordinates or paints...
// If it is not paint, returns cell that fits in hit region...
SpreadsheetCell calculatePaint(Graphics g,boolean bPaint,int xHit,int yHit) {
// Get the current size of the display area...
Dimension dm = size();
Rectangle r = null; // The clipping rectangle...
Rectangle cellRect = null; // The cell clipping rectangle...
// Calculate the cell width and height
// Cell should be wide enough to show 8 digits...
if (bPaint == true) {
cellWidth = g.getFontMetrics().stringWidth("12345.67");
cellHeight = g.getFontMetrics().getHeight();
r = g.getClipRect();
} // end if
// Figure out how many rows and cols can be displayed
int nCol = Math.min(numColumns,dm.width / cellWidth);
int nRow = Math.min((numRows + 1),dm.height / cellHeight);
// Draw the cells...
int index,i,x,j,y,currentRow,currentCol;
--nRow;
// Go across the rows...
// Show the headers and adjust for top and left cell...
for (currentRow = i = 0; i < nRow; ++i) {
y = cellHeight + (i * cellHeight);
// Go across the colomns...
for (currentCol = j = 0; j < nCol; ++j) {
index = (currentRow * numColumns) + currentCol;
x = (j * cellWidth);
// Paint if told to...
if (bPaint == true) {
// See if it is in the intersection of the
// clipping rectangle
cellRect = new Rectangle(x,y,cellWidth,cellHeight);
if (r.intersects(cellRect)) {
// Paint if we are at a valid row...
if ((currentRow < numRows) && (currentCol < numColumns)) {
matrix[index].paint(g,x,y,
cellWidth,cellHeight);
} // end inner if
else { // Otherwise fill it in with grey...
emptyCell.paint(g,x,y,cellWidth,cellHeight);
} // end else
} // end if
} // end if
else { // Otherwise see if cell fits...
if ((currentRow < numRows) && (currentCol < numColumns)) {
// See if it fits in the column...
if ((xHit >= x) && (xHit < (x + cellWidth))) {
// See if it fits in the row...
if ((yHit >= y) && (yHit < (y + cellHeight))) {
paintIndex = index;
paintX = x;
paintY = y;
return matrix[index];
} // end if
} // end if
} // end inner if
} // end else
if (j == 0)
currentCol = leftCell;
else
++currentCol;
} // end column for
// Now start data cells at appropriate top...
if (i == 0)
currentRow = topCell;
else
++currentRow;
} // end row for
return null; // Only used if paint is false...
}
// Notify parent that there is a new Highlight...
void notifyParentOfHighlight(SpreadsheetCell sc) {
// Create new event with highlight cell as arg
Event ev = new Event(this,Event.ACTION_EVENT,sc);
// Send it to the parent...
getParent().deliverEvent(ev);
}
// Handle mouse clicks to spreadsheet...
public boolean handleEvent(Event evt) {
switch(evt.id) {
// Mouse clicks. See if we should highlight
// cell on spreadsheet...
case Event.MOUSE_DOWN: {
if (evt.target instanceof SpreadsheetContainer) {
setMouseHighlight(evt.x,evt.y);
// Handle cell marking...
toggleMarking(evt.x,evt.y);
} // end if
return false;
}
case Event.MOUSE_DRAG: {
// Select cells if marking...
if (evt.target instanceof SpreadsheetContainer)
dragMarking(evt.x,evt.y);
return false;
}
case Event.MOUSE_UP: {
// If marking then we are done!
if (evt.target instanceof SpreadsheetContainer)
stopMarking(evt.x,evt.y);
return false;
}
default:
return false;
}
}
// Keep track of drag marking....
boolean marking = false;
// Keep track of whether anything is marked...
boolean markedCells = false;
// Variables to support marking operations...
SpreadsheetCell scStartMarked;
SpreadsheetCell scEndMarked;
SpreadsheetCell scCurrentMarked;
// Keep track of last marked index...
int lastTrackedIndex;
int lastMarkedIndex;
// Use for tracking painting coordinates...
int startX;
int startY;
int endX;
int endY;
int trackedX;
int trackedY;
int startMarkedRow;
int endMarkedRow;
int startMarkedCol;
int endMarkedCol;
// Return the spreadsheet cell reference if it is
// markable...
SpreadsheetCell getMarkable(int x,int y) {
SpreadsheetCell scMark = calculatePaint(null,false,x,y);
// Can't be one of the headers...
if ((scMark != null) && (scMark.getLiteral() == false) ) {
lastTrackedIndex = paintIndex;
trackedX = paintX;
trackedY = paintY;
return scMark;
}
return null;
}
// Setup marking by setting marking to false...
void setupMarking() {
marking = false;
markedCells = false;
scStartMarked = null;
scEndMarked = null;
scCurrentMarked = null;
lastTrackedIndex = -1;
lastMarkedIndex = -1;
}
// Toggle marking state...
// Either start tracking the mouse or
// Reset marking...
void toggleMarking(int x,int y) {
// If stuff has been marked before then
// turn all the marking cells off...
if (markedCells) {
resetMarking();
}
// Otherwise, start tracking the mouse...
else {
startMarking(x,y);
}
}
// Turn all the marked cells highlighting off...
void resetMarking() {
// Return if no marking...
if (markedCells == false)
return;
// Just call setNewColors with current colors..
setNewColors(normalForeColor, normalBackColor,
highlightedForeColor, highlightedBackColor);
// Set marking to false...
marking = false;
markedCells = false;
System.out.println("Reset marking");
}
// Start marking at current cell...
void startMarking(int x,int y) {
scCurrentMarked = getMarkable(x,y);
if (scCurrentMarked != null) {
System.out.println("Start marking");
scStartMarked = scCurrentMarked;
scEndMarked = scCurrentMarked;
lastMarkedIndex = lastTrackedIndex;
startX = trackedX;
startY = trackedY;
marking = true;
} // end if
// Otherwise, it is a bad cell and don't mark...
else {
System.out.println("Bad Cell: No marking");
marking = false;
markedCells = false;
}
}
// If marking is on then we need to see if a new cell
// was entered. If so, then add it the endpoint of the
// marking. If a bad cell was entered, then we are done...
void dragMarking(int x,int y) {
// Just return if marking is false...
if (!marking)
return;
// See if we entered a new cell...
if (insideCell(scCurrentMarked,x,y)) {
return;
} // end if
// If still good, see if the cell is valid
// and get its reference...
scCurrentMarked = getMarkable(x,y);
// If invalid mark is found stop marking...
if (scCurrentMarked == null) {
System.out.println("Out of bounds! Stop marking...");
marking = false;
// Make sure more than one cell is marked,
// else we have no marking...
validateMarking();
return;
}
// Validate the direction. Only let use move south eastward...
if (lastMarkedIndex >= lastTrackedIndex) {
System.out.println("Bad change of direction! Stop marking...");
marking = false;
// Make sure more than one cell is marked,
// else we have no marking...
validateMarking();
return;
}
// Otherwise, store the new cell...
scEndMarked = scCurrentMarked;
lastMarkedIndex = lastTrackedIndex;
endX = trackedX + cellWidth;
endY = trackedY + cellHeight;
System.out.println("Drag");
// Paint marked rectangle...
paintMarked();
}
// When stop marking see if more than one cell has been
// marked. If not set marking = false
public void stopMarking(int x, int y) {
// Just return if marking is false...
if (!marking)
return;
// Validate marking to see if more than one cell has been markedd...
validateMarking();
marking = false;
System.out.println("Marking done!");
}
// Make sure more than one cell is marked,
// else we have no marking...
void validateMarking() {
// If any of the pointer are null,nothing has been done...
if ((scStartMarked == null) || (scEndMarked == null) ||
(scStartMarked == scEndMarked) ){
System.out.println("No marked cells...");
markedCells = false;
return;
}
// Otherwise, we have something...
System.out.println("Validated marked cells...");
markedCells = true;
}
// Paint marked rectangle. Figure out what cells are in
// the highlighted area. Set their colors and repaint
// the area...
void paintMarked() {
// Get the starting and ending indexes into the
// matrix array...
int startIndex = getIndexFromCell(scStartMarked);
int startRow = tempRow;
int startCol = tempCol;
int endIndex = getIndexFromCell(scEndMarked);
int endRow = tempRow;
int endCol = tempCol;
startMarkedRow = startRow;
endMarkedRow = endRow;
startMarkedCol = startCol;
endMarkedCol = endCol;
if ((startIndex < 0) || (endIndex < 0)) {
return;
}
// Now go over and highlight each cell!!
int i,j,index;
// Go through the marked rows and columns...
for (i = startRow; i <= endRow; ++i) {
for (j = startCol; j <= endCol; ++j) {
index = (i * (numColumns)) + j;
// Skip over highlighted cell...
if (matrix[index] != newHighlight) {
matrix[index].setFillColor(markedBackColor);
matrix[index].setTextColor(markedForeColor);
} // end if
} // end for
} // end row for
// Repaint to force new colors to appear...
repaint(startX,startY,endX-startX,endY-startY);
}
// This is used for creating the double data and
// string values that are used to convert the cell
// container data into a graph...
// Throws an exception if nothing is marked or something
// else is wrong with the marked data...
public GraphData getGraphData() throws IllegalArgumentException {
// No cells marked is a problem...
if (!markedCells)
throw new IllegalArgumentException("No cells marked");
// Figure out how many rows were marked...
int numMarkedRows = (endMarkedRow - startMarkedRow) + 1;
int numMarkedCols = (endMarkedCol - startMarkedCol) + 1;
// Set up headings. If one row, then its the row and column
// else its the top row values...
int i,j,index;
String headings[] = new String[numMarkedCols];
// Set up using marked data in top row as headings....
if (numMarkedRows > 1) {
for (i = 0,j = startMarkedCol; j <= endMarkedCol; ++j,++i) {
index = (startMarkedRow * (numColumns)) + j;
headings[i] = matrix[index].getString();
}
}
// Otherwise use cell names as headers...
else {
index = (startMarkedRow * (numColumns));
String rowName = matrix[index].getString();
for (i = 0,j = startMarkedCol; j <= endMarkedCol; ++j,++i) {
// Take column number and convert to string...
headings[i] = rowName + String.valueOf(j - 1);
}
}
// Now load up the data. Just look at the last row...
double data[] = new double[numMarkedCols];
for (i = 0,j = startMarkedCol; j <= endMarkedCol; ++j,++i) {
index = (endMarkedRow * (numColumns)) + j;
data[i] = matrix[index].getEvalValue();
} // end for
return new GraphData(data,headings);
}
// Returns whether coordinates are within a cell...
boolean insideCell(SpreadsheetCell testCell,int x,int y) {
// Get the last coodinates of the testCell...
Rectangle r = testCell.getLastCoordinates();
if (r == null)
return false;
// Just make a rectangle and do an intersection...
Rectangle testRect = new Rectangle(x,y,0,0);
return r.intersects(testRect);
}
// Get an index from a spreadsheet cell...
int getIndexFromCell(SpreadsheetCell testCell) {
int index,i,j;
tempRow = tempCol = 0;
for (i = 0; i < numRows; ++i) {
for (j = 0; j < numColumns; ++j) {
index = (i * (numColumns)) + j;
// See if the cells match...
if (matrix[index] == testCell) {
tempRow = i;
tempCol = j;
return index;
} // end if
} // end inner for...
} // end outer for
return -1;
}
// Handle to change to a formula...
// Throws an exception if the formula is invalid...
public void replaceFormula(SpreadsheetCell sc,String newFormula) throws IllegalArgumentException {
String convertedFormula;
// First validate the formula...
try {
convertedFormula = c.validateFormula(sc.getCell(),newFormula);
}
// If formula is invalid, rethrow an exception...
catch (FormulaParserException e) {
throw new IllegalArgumentException();
}
// Add converted formula to cell...
sc.setString(convertedFormula);
// Recalc... Set hourglass...
c.recalculateAll();
// Repaint...
repaint();
}
// Routines for getting the various color display values...
public Color getNormalForeColor() {
return normalForeColor;
}
public Color getNormalBackColor() {
return normalBackColor;
}
public Color getHighlightedForeColor() {
return highlightedForeColor;
}
public Color getHighlightedBackColor() {
return highlightedBackColor;
}
// Set the new colors for the spreadsheet
// Set for each cell and then repaint...
public void setNewColors(Color normalFore, Color normalBack,
Color highlightFore, Color highlightBack) {
// Set the internal color variables...
normalForeColor = normalFore;
normalBackColor = normalBack;
highlightedForeColor = highlightFore;
highlightedBackColor = highlightBack;
// Reload the colors for the matrix
int index;
for (int i = 1; i < numRows; ++i) {
for (int j = 1; j < numColumns; ++j) {
index = (i * (numColumns)) + j;
// Set the colors...
matrix[index].setFillColor(normalBackColor);
matrix[index].setTextColor(normalForeColor);
} // end inner for...
} // end outer for
// Reload the color for the highlight...
newHighlight.setFillColor(highlightedBackColor);
newHighlight.setTextColor(highlightedForeColor);
// Now repaint everything...
repaint();
}
// Set the font for all the individual
// spreadsheet cells...
public synchronized void setFont(Font f) {
super.setFont(f);
int index;
// Reload the font for each cell...
for (int i = 0; i < numRows; ++i) {
for (int j = 0; j < numColumns; ++j) {
index = (i * (numColumns)) + j;
// Set the colors...
matrix[index].setFont(f);
} // end inner for...
} // end outer for
// Repaint to show new font...
repaint();
}
}
=============================
Tidak ada komentar:
Posting Komentar