Skip to content

Commit 5033ba1

Browse files
author
Thomas Nijssen
committed
Merge pull request #1 from thomas9n127/exp
Exp
2 parents 7bd9421 + cb8b51f commit 5033ba1

File tree

9 files changed

+229
-41
lines changed

9 files changed

+229
-41
lines changed

nbproject/build-impl.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -834,7 +834,7 @@ is divided into following sections:
834834
</chainedmapper>
835835
</pathconvert>
836836
<taskdef classname="org.netbeans.modules.java.j2seproject.copylibstask.CopyLibs" classpath="${libs.CopyLibs.classpath}" name="copylibs"/>
837-
<copylibs compress="${jar.compress}" excludeFromCopy="${copylibs.excludes}" index="${jar.index}" indexMetaInf="${jar.index.metainf}" jarfile="${dist.jar}" manifest="@{manifest}" rebase="${copylibs.rebase}" runtimeclasspath="${run.classpath.without.build.classes.dir}">
837+
<copylibs compress="${jar.compress}" index="${jar.index}" indexMetaInf="${jar.index.metainf}" jarfile="${dist.jar}" manifest="@{manifest}" rebase="${copylibs.rebase}" runtimeclasspath="${run.classpath.without.build.classes.dir}">
838838
<fileset dir="${build.classes.dir}" excludes="${dist.archive.excludes}"/>
839839
<manifest>
840840
<attribute name="Class-Path" value="${jar.classpath}"/>

src/textexcel/CellMatrix.java

Lines changed: 60 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -10,12 +10,10 @@
1010
* @author thomas
1111
*/
1212
public class CellMatrix {
13-
1413
private Cell[][] data;
1514
private ArrayList<String> cellNames;
1615
private static final int COLUMN_WIDTH = 12;
17-
private static final String CELL_CLASSES_PREFIX = "textexcel.cell.";
18-
private static final String CELL_CLASSES = "DoubleCell,DateCell,StringCell";
16+
private static final Class[] CELL_CLASSES = { FormulaCell.class, DoubleCell.class, DateCell.class, StringCell.class };
1917
private static final String FILE_RECORD_SEPERATOR = ";";
2018

2119
/**
@@ -24,13 +22,27 @@ public class CellMatrix {
2422
* @author thomas
2523
* @returns new CellMatrix class
2624
*/
27-
public CellMatrix(int width, int height) {
25+
private CellMatrix(int width, int height) {
2826
this.data = new Cell[height][width]; //TODO support more types
2927
this.cellNames = new ArrayList<>();
3028
this.setCellNames();
3129
this.setDefaultValues();
3230
}
31+
32+
public static CellMatrix newInstance(int width, int height) {
33+
CellMatrix m = new CellMatrix(width, height);
34+
CellMatrixSingletonHolder.INSTANCE = m;
35+
return m;
36+
}
37+
38+
public static CellMatrix getInstance() {
39+
return CellMatrixSingletonHolder.INSTANCE;
40+
}
3341

42+
public ArrayList<String> getCellNames() {
43+
return this.cellNames;
44+
}
45+
3446
private void setCellNames() {
3547
for(int i = 0; i < this.data.length; i++) {
3648
for(int j = 0; j < this.data[0].length; j++) {
@@ -91,7 +103,6 @@ public void setDefaultValues() {
91103
this.data[i][j] = new StringCell("");
92104
}
93105
}
94-
95106
}
96107

97108
private Coordinate cellNameToCoord(String cellName) {
@@ -103,8 +114,8 @@ private Coordinate cellNameToCoord(String cellName) {
103114

104115
//convert into a coordinates
105116
Coordinate ret = new Coordinate();
106-
ret.row = cellIndex / this.data.length;
107-
ret.column = cellIndex % this.data.length;
117+
ret.row = cellIndex / this.data[0].length;
118+
ret.column = cellIndex % this.data[0].length;
108119

109120
return ret;
110121
}
@@ -117,34 +128,39 @@ public void set(String cellName, String expr) throws Exception {
117128

118129
public void set(int cellIndexR, int cellIndexC, String expr) throws Exception {
119130
//Try to fit the expression to each type of cell
120-
for(String cn : CELL_CLASSES.split(",")) {
131+
for(Class classToTry : CELL_CLASSES) {
121132
Cell that = null;
122133
try {
123-
that = (Cell) Class.forName(CELL_CLASSES_PREFIX + cn).newInstance();
134+
that = (Cell) classToTry.newInstance();
124135
that.set(expr); //this will fail if the input isn't the right type for it
125136
} catch(InstantiationException | ExceptionInInitializerError ie) {
126137
throw new Exception("Instantiation failed: " + ie.getMessage());
138+
} catch(FormulaCellException fe) {
139+
throw new Exception("Error parsing formula: " + fe.getMessage());
127140
} catch(Exception e) {
128141
continue; //try the next one
129142
}
130143

131-
this.data[cellIndexR][cellIndexC] = (Cell)that; //only happens if prev is success
144+
this.data[cellIndexR][cellIndexC] = that; //only happens if prev is success
132145
return;
133146
}
134147

135-
throw new Exception("No suitable data type found.");
148+
throw new Exception("There is no cell type available for that expression");
136149
}
137150

138151
public String get(String cellName) {
152+
return this.get(cellName, true);
153+
}
154+
155+
public String get(String cellName, boolean showCellType) {
139156
Coordinate c = this.cellNameToCoord(cellName);
140-
141-
return this.get(c.row, c.column);
157+
return this.get(c.row, c.column, showCellType);
142158
}
143159

144-
private String get(int row, int column) {
145-
return this.data[row][column].getDisplayValue(0);
160+
private String get(int row, int column, boolean showCellType) {
161+
return this.data[row][column].getDisplayValue(showCellType ? 0 : -1);
146162
}
147-
163+
148164
public void clear(String cellName) throws Exception {
149165
Coordinate c = this.cellNameToCoord(cellName);
150166

@@ -176,15 +192,41 @@ public String[] getSaveData() {
176192
public void loadFrom(String[] input) throws Exception {
177193
for(int r = 0; r < this.data.length; r++) {
178194
String[] cellStrings = input[r].split(FILE_RECORD_SEPERATOR);
179-
for(int c = 0; r < this.data[0].length; c++) {
195+
for(int c = 0; c < this.data[0].length; c++) {
180196
this.set(r, c, cellStrings[c]);
181197
}
182198
}
183199
}
184200

201+
public ArrayList<Cell> getRectangularRange(String lowerName, String upperName) {
202+
Coordinate lowerCoord = this.cellNameToCoord(lowerName);
203+
Coordinate upperCoord = this.cellNameToCoord(upperName);
204+
205+
//Check to make sure they're the right way around
206+
if(lowerCoord.row > upperCoord.row || lowerCoord.column > upperCoord.column) {
207+
//switch them
208+
Coordinate tmp = lowerCoord;
209+
lowerCoord = upperCoord;
210+
upperCoord = tmp;
211+
}
212+
213+
ArrayList<Cell> range = new ArrayList<>();
214+
for(int r = lowerCoord.row; r <= upperCoord.row; r++) {
215+
for(int c = lowerCoord.column; c <= upperCoord.column; c++) {
216+
range.add(this.data[r][c]);
217+
}
218+
}
219+
220+
return range;
221+
}
222+
185223
//If only Java had structs...
186224
private static class Coordinate {
187225
public int row;
188226
public int column;
189-
}
227+
}
228+
229+
private static class CellMatrixSingletonHolder {
230+
private static CellMatrix INSTANCE;
231+
}
190232
}

src/textexcel/TextExcel.java

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,13 @@ public class TextExcel {
1616
public static void main(String[] args) throws Exception {
1717
Scanner sc = new Scanner(System.in);
1818

19-
matrix = new CellMatrix(10, 10);
19+
matrix = CellMatrix.newInstance(6, 2);
20+
21+
evaluateExpression("A1 = 100");
22+
evaluateExpression("A2 = ( A1 * 2 )");
23+
evaluateExpression("B1 = ( A1 + 2 )");
24+
evaluateExpression("B2 = 50");
25+
evaluateExpression("C1 = ( sum A1 - B2 )");
2026

2127
while (true) {
2228
System.out.print("Enter a command: ");
@@ -27,7 +33,6 @@ public static void main(String[] args) throws Exception {
2733
System.err.println(e.getMessage() + "\n");
2834
}
2935
}
30-
3136
}
3237

3338
private static void evaluateExpression(String line) throws Exception {

src/textexcel/cell/Cell.java

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ public void clear() {
3535
* @return
3636
*/
3737
public String getDisplayValue(int length) {
38-
String cv = this.computeValue();
38+
String cv = this.get().toString();
3939

4040
if (cv != null && cv.length() == 0 && length == 0) {
4141
return "<empty>";
@@ -45,6 +45,10 @@ public String getDisplayValue(int length) {
4545
//special case for string cell in which we need quotes
4646
String quotes = this instanceof StringCell ? "\"" : "";
4747
return quotes + cv + quotes + "\n" + this.getClassType();
48+
} else if(cv != null && length < 0) {
49+
//like previous, but without the nonsense of the cell type
50+
String quotes = this instanceof StringCell ? "\"" : "";
51+
return quotes + cv + quotes;
4852
} else {
4953
//truncate to length
5054
if (cv.length() > 12) {
@@ -62,14 +66,10 @@ public String getDisplayValue(int length) {
6266
}
6367
}
6468

65-
protected String computeValue() {
66-
return this.value.toString();
67-
}
68-
6969
private String getClassType() {
7070
String cn = this.getClass().getName();
7171
String name = cn.substring(cn.lastIndexOf('.') + 1, cn.indexOf("Cell"));
72-
name = (this instanceof DoubleCell) ? "Number" : name; //we'll kindly call this a "special" case...
72+
name = (this instanceof DoubleCell) ? "Number" : name; //because the requirements say so
7373
return "[" + name + "]";
7474
}
7575
}

src/textexcel/cell/DateCell.java

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,6 @@
33
import java.text.SimpleDateFormat;
44

55
public class DateCell extends Cell {
6-
//private Date value;
7-
86
private final static String DATE_FORMAT = "MM/dd/yyyy";
97
private final SimpleDateFormat sdf;
108

@@ -16,11 +14,6 @@ public DateCell() {
1614
public void set(String expr) throws Exception {
1715
super.set(expr);
1816

19-
this.value = this.sdf.parse(expr);
20-
}
21-
22-
@Override
23-
protected String computeValue() {
24-
return this.sdf.format(this.value);
17+
this.value = this.sdf.format(this.sdf.parse(expr));
2518
}
2619
}

src/textexcel/cell/DoubleCell.java

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,6 @@
55
* @author thomas
66
*/
77
public class DoubleCell extends Cell {
8-
//private double value;
9-
108
/**
119
* Create a new DoubleCell class.
1210
*

src/textexcel/cell/FormulaCell.java

Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
package textexcel.cell;
2+
3+
import java.util.ArrayList;
4+
import java.util.Iterator;
5+
import java.util.StringTokenizer;
6+
import java.util.logging.Level;
7+
import java.util.logging.Logger;
8+
import javax.script.*;
9+
import textexcel.CellMatrix;
10+
11+
/**
12+
*
13+
* @author thomas
14+
*/
15+
public class FormulaCell extends Cell {
16+
17+
private ScriptEngine scriptEngine;
18+
19+
/**
20+
* Create a new FormulaCell class.
21+
*
22+
* @author thomas
23+
* @returns new FormulaCell class
24+
*/
25+
public FormulaCell() {
26+
this.value = 0.0;
27+
28+
//Init ScriptEngine to evaluate the formula
29+
ScriptEngineManager sem = new ScriptEngineManager();
30+
scriptEngine = sem.getEngineByMimeType("text/javascript");
31+
}
32+
33+
@Override
34+
public void set(String expr) throws Exception {
35+
if (!expressionIsFormula(expr)) {
36+
throw new Exception("That is not a formula");
37+
}
38+
super.set(expr);
39+
this.evaluateFormula();
40+
}
41+
42+
private static boolean expressionIsFormula(String expr) {
43+
if (expr.charAt(0) == '(' && expr.charAt(expr.length() - 1) == ')') {
44+
return true;
45+
}
46+
return false;
47+
}
48+
49+
private void evaluateFormula() throws Exception {
50+
//remove parentheses for ease
51+
String exprTmp = expr.substring(1, expr.length() - 2);
52+
String[] exprParts = exprTmp.trim().split("\\s");
53+
54+
if ((exprParts[0].equals("sum") || exprParts[0].equals("avg")) && exprParts[2].equals("-")) {
55+
ArrayList<Cell> range = CellMatrix.getInstance().getRectangularRange(exprParts[1], exprParts[3]);
56+
this.value = divideCellRange(range, exprParts[0].equals("avg") ? range.size() : 1);
57+
} else {
58+
this.evaluateArithmeticFormula();
59+
}
60+
}
61+
62+
private void evaluateArithmeticFormula() throws Exception {
63+
Bindings b = this.scriptEngine.createBindings();
64+
CellMatrix theMatrix = CellMatrix.getInstance(); //get the CellMatrix instance
65+
66+
for (Iterator<String> it = theMatrix.getCellNames().iterator(); it.hasNext();) {
67+
String cellName = it.next();
68+
try {
69+
b.put(cellName, Double.parseDouble(theMatrix.get(cellName, false)));
70+
} catch (Exception e) {
71+
continue; //not something that can be used in a formula
72+
}
73+
}
74+
75+
//Now evaluate it, and set the value
76+
try {
77+
this.scriptEngine.eval("var RET = " + this.expr + ";", b);
78+
this.value = b.get("RET");
79+
} catch (ScriptException e) {
80+
throw new FormulaCellException("Error in evaluating: " + e.getMessage());
81+
}
82+
}
83+
84+
private static double divideCellRange(ArrayList<Cell> range, int n) throws FormulaCellException {
85+
double total = 0.0;
86+
try {
87+
for (Cell c : range) {
88+
total += Double.parseDouble(c.getDisplayValue(-1));
89+
}
90+
} catch (Exception e) {
91+
throw new FormulaCellException("One of these cells was not a number");
92+
}
93+
94+
return total / n;
95+
}
96+
}
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
package textexcel.cell;
2+
3+
/**
4+
*
5+
* @author Thomas Nijssen
6+
*/
7+
public class FormulaCellException extends Exception {
8+
9+
/**
10+
* Creates a new instance of
11+
* <code>FormulaCellException</code> without detail message.
12+
*/
13+
public FormulaCellException() {
14+
}
15+
16+
/**
17+
* Constructs an instance of
18+
* <code>FormulaCellException</code> with the specified detail message.
19+
*
20+
* @param msg the detail message.
21+
*/
22+
public FormulaCellException(String msg) {
23+
super(msg);
24+
}
25+
}

0 commit comments

Comments
 (0)