new Value interface

This commit is contained in:
Denis Molony 2016-03-16 17:15:39 +11:00
parent 49c66918e1
commit b87609c9d0
22 changed files with 266 additions and 267 deletions

View File

@ -2,33 +2,14 @@ package com.bytezone.diskbrowser.visicalc;
public class Abs extends Function public class Abs extends Function
{ {
private boolean hasChecked;
private double value = 0;
Abs (Sheet parent, String text) Abs (Sheet parent, String text)
{ {
super (parent, text); super (parent, text);
} }
@Override @Override
public boolean hasValue () public void calculate ()
{ {
if (!hasChecked)
calculate ();
return hasValue;
}
@Override
public double getValue ()
{
return hasValue () ? value : 0;
}
private void calculate ()
{
hasChecked = true;
hasValue = true;
Expression exp = new Expression (parent, functionText); Expression exp = new Expression (parent, functionText);
value = Math.abs (exp.getValue ()); value = Math.abs (exp.getValue ());
} }

View File

@ -9,8 +9,8 @@ class And extends Function
} }
@Override @Override
public double getValue () public void calculate ()
{ {
return 0; value = 0;
} }
} }

View File

@ -28,6 +28,7 @@ class Cell implements Comparable<Cell>, Value
{ {
this.parent = parent; this.parent = parent;
this.address = address; this.address = address;
type = CellType.VALUE; // default to VALUE, formatting may change it
} }
public boolean isValue () public boolean isValue ()
@ -110,8 +111,8 @@ class Cell implements Comparable<Cell>, Value
String getText (int colWidth, char defaultFormat) String getText (int colWidth, char defaultFormat)
{ {
// cell may have been created when formatted but no type set // cell may have been created when formatted but no type set
if (type == null) // if (type == null)
return justify ("", colWidth); // return justify ("", colWidth);
switch (type) switch (type)
{ {
@ -122,47 +123,43 @@ class Cell implements Comparable<Cell>, Value
return justify (repeat, colWidth); return justify (repeat, colWidth);
case VALUE: case VALUE:
if (hasValue ()) if (value.isError () || value.isNaN ())
{ return justify (value.getText (), colWidth);
Double value = getValue ();
if (Double.isNaN (value))
return justify ("", colWidth);
char format = cellFormat != ' ' ? cellFormat : defaultFormat; Double thisValue = value.getValue ();
if (format == 'I')
{ char format = cellFormat != ' ' ? cellFormat : defaultFormat;
String integerFormat = String.format ("%%%d.0f", colWidth); if (format == 'I')
return String.format (integerFormat, value); {
} String integerFormat = String.format ("%%%d.0f", colWidth);
else if (format == '$') return String.format (integerFormat, thisValue);
{ }
String currencyFormat = String.format ("%%%d.%ds", colWidth, colWidth); else if (format == '$')
return String.format (currencyFormat, nf.format (value)); {
} String currencyFormat = String.format ("%%%d.%ds", colWidth, colWidth);
else if (format == '*') return String.format (currencyFormat, nf.format (thisValue));
{ }
String graphFormat = String.format ("%%-%d.%ds", colWidth, colWidth); else if (format == '*')
// this is not finished {
return String.format (graphFormat, "********************"); String graphFormat = String.format ("%%-%d.%ds", colWidth, colWidth);
} // this is not finished
else return String.format (graphFormat, "********************");
{ }
// this could be improved else
String numberFormat = String.format ("%%%d.3f", colWidth + 4); {
String val = String.format (numberFormat, value); // this could be improved
while (val.endsWith ("0")) String numberFormat = String.format ("%%%d.3f", colWidth + 4);
val = ' ' + val.substring (0, val.length () - 1); String val = String.format (numberFormat, thisValue);
if (val.endsWith (".")) while (val.endsWith ("0"))
val = ' ' + val.substring (0, val.length () - 1); val = ' ' + val.substring (0, val.length () - 1);
if (val.length () > colWidth) if (val.endsWith ("."))
val = val.substring (val.length () - colWidth); val = ' ' + val.substring (0, val.length () - 1);
return val; if (val.length () > colWidth)
} val = val.substring (val.length () - colWidth);
return val;
} }
// else
// return justify ("", colWidth);
} }
return getError (); return getText ();
} }
private String justify (String text, int colWidth) private String justify (String text, int colWidth)
@ -177,40 +174,48 @@ class Cell implements Comparable<Cell>, Value
return (String.format (labelFormat, text)); return (String.format (labelFormat, text));
} }
@Override
public boolean hasValue ()
{
if (type == CellType.VALUE)
return value.hasValue ();
return false;
}
// this should be called when doing calculations
@Override @Override
public double getValue () public double getValue ()
{ {
if (type != CellType.VALUE) assert type == CellType.VALUE;
return 0;
return value.getValue (); return value.getValue ();
} }
@Override @Override
public String getError () public String getText ()
{ {
return value.getError (); assert type == CellType.VALUE;
return value.getText ();
} }
void calculate () @Override
public boolean isError ()
{ {
assert type == CellType.VALUE;
return value.isError ();
}
@Override
public boolean isNaN ()
{
assert type == CellType.VALUE;
return value.isNaN ();
}
@Override
public void calculate ()
{
assert type == CellType.VALUE;
if (expressionText == null) if (expressionText == null)
{ {
System.out.printf ("%s null expression text %n", address); System.out.printf ("%s null expression text %n", address);
value = Function.getInstance (parent, "@ERROR()"); value = Function.getInstance (parent, "@ERROR");
} }
else else
// could use Number or Cell for simple Values // should use Number or Cell for simple Values
value = new Expression (parent, expressionText); value = new Expression (parent, expressionText);
value.calculate ();
} }
@Override @Override

View File

@ -3,8 +3,6 @@ package com.bytezone.diskbrowser.visicalc;
class Count extends Function class Count extends Function
{ {
private final Range range; private final Range range;
private boolean hasChecked;
private double count = 0;
public Count (Sheet parent, String text) public Count (Sheet parent, String text)
{ {
@ -13,33 +11,20 @@ class Count extends Function
} }
@Override @Override
public boolean hasValue () public void calculate ()
{ {
if (!hasChecked) value = 0;
calculate ();
return hasValue;
}
@Override
public double getValue ()
{
return hasValue () ? count : 0;
}
private void calculate ()
{
hasChecked = true;
hasValue = false;
for (Address address : range) for (Address address : range)
{ {
Cell cell = parent.getCell (address); Cell cell = parent.getCell (address);
if (cell != null && cell.hasValue ()) if (cell == null || cell.isError () || cell.isNaN ())
{ {
hasValue = true; isError = true;
if (cell.getValue () != 0.0) break;
count++;
} }
if (cell.getValue () != 0.0)
value++;
} }
} }
} }

View File

@ -8,15 +8,15 @@ class Error extends Function
} }
@Override @Override
public boolean hasValue () public boolean isError ()
{ {
return false; return true;
} }
@Override @Override
public String getError () public boolean isNaN ()
{ {
return "@Error"; return true;
} }
@Override @Override
@ -24,4 +24,9 @@ class Error extends Function
{ {
return 0; return 0;
} }
@Override
public void calculate ()
{
}
} }

View File

@ -32,7 +32,8 @@ class Expression implements Value
private final List<String> operators = new ArrayList<String> (); private final List<String> operators = new ArrayList<String> ();
private final List<String> signs = new ArrayList<String> (); private final List<String> signs = new ArrayList<String> ();
private boolean hasValue; protected boolean isError;
private double value;
public Expression (Sheet parent, String text) public Expression (Sheet parent, String text)
{ {
@ -112,14 +113,13 @@ class Expression implements Value
} }
assert values.size () > 0; assert values.size () > 0;
hasValue = true;
} }
@Override @Override
public double getValue () public void calculate ()
{ {
Value thisValue = values.get (0); Value thisValue = values.get (0);
double value = thisValue == null ? 0 : values.get (0).getValue (); value = thisValue == null ? 0 : values.get (0).getValue ();
String sign = signs.get (0); String sign = signs.get (0);
if (sign.equals ("(-)")) if (sign.equals ("(-)"))
@ -146,21 +146,36 @@ class Expression implements Value
else if (operator.equals ("^")) else if (operator.equals ("^"))
value = Math.pow (value, nextValue); value = Math.pow (value, nextValue);
} }
}
@Override
public boolean isNaN ()
{
return Double.isNaN (value);
}
@Override
public String getText ()
{
if (isNaN ())
return "NaN";
if (isError ())
return "Error";
return "";
}
@Override
public boolean isError ()
{
return isError;
}
@Override
public double getValue ()
{
return value; return value;
} }
@Override
public boolean hasValue ()
{
return hasValue;
}
@Override
public String getError ()
{
return hasValue ? "" : "Error";
}
private String checkBrackets (String input) private String checkBrackets (String input)
{ {
String line = input.trim (); String line = input.trim ();

View File

@ -32,7 +32,9 @@ abstract class Function implements Value
protected final Sheet parent; protected final Sheet parent;
protected String functionText; protected String functionText;
protected boolean hasValue;
protected boolean isError;
protected double value;
static Function getInstance (Sheet parent, String text) static Function getInstance (Sheet parent, String text)
{ {
@ -95,19 +97,37 @@ abstract class Function implements Value
// get function's parameter string // get function's parameter string
int pos = text.indexOf ('('); int pos = text.indexOf ('(');
if (pos >= 0) if (pos >= 0)
this.functionText = text.substring (pos + 1, text.length () - 1); functionText = text.substring (pos + 1, text.length () - 1);
else
functionText = "";
} }
@Override @Override
public boolean hasValue () public boolean isError ()
{ {
return hasValue; return isError;
} }
@Override @Override
public String getError () public boolean isNaN ()
{ {
return hasValue ? "" : "Error"; return Double.isNaN (value);
}
@Override
public double getValue ()
{
return value;
}
@Override
public String getText ()
{
if (isNaN ())
return "NaN";
if (isError ())
return "Error";
return "";
} }
protected Range getRange (String text) protected Range getRange (String text)

View File

@ -15,25 +15,27 @@ class If extends Function
int pos1 = functionText.indexOf (','); int pos1 = functionText.indexOf (',');
int pos2 = functionText.indexOf (',', pos1 + 1); int pos2 = functionText.indexOf (',', pos1 + 1);
condition = new Condition (parent, functionText.substring (0, pos1)); condition = new Condition (parent, functionText.substring (0, pos1));
textTrue = functionText.substring (pos1 + 1, pos2); textTrue = functionText.substring (pos1 + 1, pos2);
textFalse = functionText.substring (pos2 + 1); textFalse = functionText.substring (pos2 + 1);
} }
@Override @Override
public double getValue () public void calculate ()
{ {
if (condition.getResult ()) if (condition.getResult ())
{ {
if (expTrue == null) if (expTrue == null)
expTrue = new Expression (parent, textTrue); expTrue = new Expression (parent, textTrue);
return expTrue.getValue (); value = expTrue.getValue ();
} }
else else
{ {
if (expFalse == null) if (expFalse == null)
expFalse = new Expression (parent, textFalse); expFalse = new Expression (parent, textFalse);
return expFalse.getValue (); value = expFalse.getValue ();
} }
} }

View File

@ -9,8 +9,9 @@ public class Int extends Function
} }
@Override @Override
public double getValue () public void calculate ()
{ {
return 0; Expression exp = new Expression (parent, functionText);
value = (int) exp.getValue ();
} }
} }

View File

@ -2,22 +2,18 @@ package com.bytezone.diskbrowser.visicalc;
class IsError extends Function class IsError extends Function
{ {
boolean firstTime = true; Expression expression;
Cell cell;
public IsError (Sheet parent, String text) public IsError (Sheet parent, String text)
{ {
super (parent, text); super (parent, text);
expression = new Expression (parent, functionText);
} }
@Override @Override
public double getValue () public void calculate ()
{ {
if (firstTime) value = expression.getValue ();
{ isError = expression.isError ();
firstTime = false;
cell = parent.getCell (new Address (functionText));
}
return cell == null ? 1 : 0;
} }
} }

View File

@ -2,15 +2,18 @@ package com.bytezone.diskbrowser.visicalc;
public class IsNa extends Function public class IsNa extends Function
{ {
Expression expression;
IsNa (Sheet parent, String text) IsNa (Sheet parent, String text)
{ {
super (parent, text); super (parent, text);
expression = new Expression (parent, functionText);
} }
@Override @Override
public double getValue () public void calculate ()
{ {
return 0; value = expression.getValue ();
isError = expression.isError ();
} }
} }

View File

@ -3,7 +3,7 @@ package com.bytezone.diskbrowser.visicalc;
class Lookup extends Function class Lookup extends Function
{ {
Range range; Range range;
boolean hasValue; // boolean hasValue;
String sourceText; String sourceText;
String rangeText; String rangeText;
Expression source; Expression source;
@ -21,14 +21,13 @@ class Lookup extends Function
} }
// need a mechanism to return NA and ERROR // need a mechanism to return NA and ERROR
@Override // @Override
public boolean hasValue () // public boolean hasValue ()
{ // {
return hasValue; // return hasValue;
} // }
@Override public void calculate ()
public double getValue ()
{ {
double sourceValue = source.getValue (); double sourceValue = source.getValue ();
@ -43,10 +42,10 @@ class Lookup extends Function
if (target != null) if (target != null)
if (range.isVertical ()) if (range.isVertical ())
return parent.getCell (target.nextColumn ()).getValue (); value = parent.getCell (target.nextColumn ()).getValue ();
else else
return parent.getCell (target.nextRow ()).getValue (); value = parent.getCell (target.nextRow ()).getValue ();
return 0; // return 0;
} }
} }

View File

@ -3,8 +3,6 @@ package com.bytezone.diskbrowser.visicalc;
class Max extends Function class Max extends Function
{ {
private final Range range; private final Range range;
private boolean hasChecked;
private double max = Double.MIN_VALUE;
public Max (Sheet parent, String text) public Max (Sheet parent, String text)
{ {
@ -13,34 +11,31 @@ class Max extends Function
} }
@Override @Override
public boolean hasValue () public void calculate ()
{ {
if (!hasChecked) value = Double.MIN_VALUE;
calculate (); isError = false;
return hasValue; int totalChecked = 0;
}
@Override
public double getValue ()
{
return hasValue () ? max : 0;
}
private void calculate ()
{
hasChecked = true;
hasValue = false;
for (Address address : range) for (Address address : range)
{ {
Cell cell = parent.getCell (address); Cell cell = parent.getCell (address);
if (cell != null && cell.hasValue ()) if (cell == null)
continue;
if (cell.isError () || cell.isNaN ())
{ {
hasValue = true; isError = true;
double value = cell.getValue (); break;
if (value > max)
max = value;
} }
double temp = cell.getValue ();
if (temp > value)
value = temp;
totalChecked++;
} }
if (totalChecked == 0)
isError = true;
} }
} }

View File

@ -3,8 +3,6 @@ package com.bytezone.diskbrowser.visicalc;
class Min extends Function class Min extends Function
{ {
private final Range range; private final Range range;
private boolean hasChecked;
private double min = Double.MAX_VALUE;
public Min (Sheet parent, String text) public Min (Sheet parent, String text)
{ {
@ -13,34 +11,31 @@ class Min extends Function
} }
@Override @Override
public boolean hasValue () public void calculate ()
{ {
if (!hasChecked) value = Double.MAX_VALUE;
calculate (); isError = false;
return hasValue; int totalChecked = 0;
}
@Override
public double getValue ()
{
return hasValue () ? min : 0;
}
private void calculate ()
{
hasChecked = true;
hasValue = false;
for (Address address : range) for (Address address : range)
{ {
Cell cell = parent.getCell (address); Cell cell = parent.getCell (address);
if (cell != null && cell.hasValue ()) if (cell == null)
continue;
if (cell.isError () || cell.isNaN ())
{ {
hasValue = true; isError = true;
double value = cell.getValue (); break;
if (value < min)
min = value;
} }
double temp = cell.getValue ();
if (temp < value)
value = temp;
totalChecked++;
} }
if (totalChecked == 0)
isError = true;
} }
} }

View File

@ -8,15 +8,15 @@ public class Na extends Function
} }
@Override @Override
public boolean hasValue () public boolean isError ()
{ {
return false; return true;
} }
@Override @Override
public String getError () public boolean isNaN ()
{ {
return "@NA"; return true;
} }
@Override @Override
@ -24,4 +24,9 @@ public class Na extends Function
{ {
return 0; return 0;
} }
@Override
public void calculate ()
{
}
} }

View File

@ -8,9 +8,6 @@ public class Npv extends Function
private final Expression valueExp; private final Expression valueExp;
private final Range range; private final Range range;
private boolean hasChecked;
private final double value = 0;
Npv (Sheet parent, String text) Npv (Sheet parent, String text)
{ {
super (parent, text); super (parent, text);
@ -24,32 +21,23 @@ public class Npv extends Function
} }
@Override @Override
public boolean hasValue () public void calculate ()
{ {
if (!hasChecked) value = 0;
calculate ();
return hasValue;
}
@Override
public double getValue ()
{
return hasValue () ? value : 0;
}
private void calculate ()
{
hasChecked = true;
hasValue = false;
for (Address address : range) for (Address address : range)
{ {
Cell cell = parent.getCell (address); Cell cell = parent.getCell (address);
if (cell != null && cell.hasValue ()) if (cell == null)
continue;
if (cell.isError () || cell.isNaN ())
{ {
hasValue = true; isError = true;
// calculate something break;
} }
double temp = cell.getValue ();
} }
} }
} }

View File

@ -2,26 +2,37 @@ package com.bytezone.diskbrowser.visicalc;
class Number implements Value class Number implements Value
{ {
private double value; double value;
private boolean hasValue; boolean isError;
public Number (String text) public Number (String text)
{ {
try try
{ {
this.value = Double.parseDouble (text); value = Double.parseDouble (text);
hasValue = true;
} }
catch (NumberFormatException e) catch (NumberFormatException e)
{ {
hasValue = false; isError = true;
} }
} }
@Override @Override
public boolean hasValue () public boolean isError ()
{ {
return hasValue; return isError;
}
@Override
public boolean isNaN ()
{
return Double.isNaN (value);
}
@Override
public String toString ()
{
return String.format ("Number: %f", value);
} }
@Override @Override
@ -31,14 +42,13 @@ class Number implements Value
} }
@Override @Override
public String getError () public String getText ()
{ {
return hasValue ? "" : "@NA"; return null;
} }
@Override @Override
public String toString () public void calculate ()
{ {
return String.format ("Number: %f", value);
} }
} }

View File

@ -9,8 +9,8 @@ class Or extends Function
} }
@Override @Override
public double getValue () public void calculate ()
{ {
return 0; value = 0;
} }
} }

View File

@ -8,8 +8,8 @@ class Pi extends Function
} }
@Override @Override
public double getValue () public void calculate ()
{ {
return 3.1415926536; value = 3.1415926536;
} }
} }

View File

@ -14,6 +14,7 @@ public class Sheet
private static final Pattern addressPattern = private static final Pattern addressPattern =
Pattern.compile ("([AB]?[A-Z])([0-9]{1,3}):"); Pattern.compile ("([AB]?[A-Z])([0-9]{1,3}):");
private static final byte END_OF_LINE_TOKEN = (byte) 0x8D; private static final byte END_OF_LINE_TOKEN = (byte) 0x8D;
private static final int FORMAT_LENGTH = 3;
private final Map<Integer, Cell> rowOrderCells = new TreeMap<Integer, Cell> (); private final Map<Integer, Cell> rowOrderCells = new TreeMap<Integer, Cell> ();
private final Map<Integer, Cell> columnOrderCells = new TreeMap<Integer, Cell> (); private final Map<Integer, Cell> columnOrderCells = new TreeMap<Integer, Cell> ();
@ -266,7 +267,8 @@ public class Sheet
String format = ""; String format = "";
while (line.startsWith ("/")) while (line.startsWith ("/"))
{ {
String fmt = line.substring (0, 3); String fmt = line.substring (0, FORMAT_LENGTH);
line = line.substring (FORMAT_LENGTH);
if (fmt.equals ("/TH") || fmt.equals ("/TV")) // lock titles ?? if (fmt.equals ("/TH") || fmt.equals ("/TV")) // lock titles ??
{ {
@ -275,7 +277,6 @@ public class Sheet
else else
currentCell.format (fmt); // formatting command currentCell.format (fmt); // formatting command
line = line.substring (3);
format += fmt; format += fmt;
} }

View File

@ -3,8 +3,6 @@ package com.bytezone.diskbrowser.visicalc;
class Sum extends Function class Sum extends Function
{ {
private final Range range; private final Range range;
private boolean hasChecked;
private double sum = 0;
public Sum (Sheet parent, String text) public Sum (Sheet parent, String text)
{ {
@ -13,32 +11,21 @@ class Sum extends Function
} }
@Override @Override
public boolean hasValue ()
{
if (!hasChecked)
calculate ();
return hasValue;
}
@Override
public double getValue ()
{
return hasValue () ? sum : 0;
}
public void calculate () public void calculate ()
{ {
hasChecked = true; value = 0;
hasValue = false;
for (Address address : range) for (Address address : range)
{ {
Cell cell = parent.getCell (address); Cell cell = parent.getCell (address);
if (cell != null && cell.hasValue ()) if (cell == null)
continue;
if (cell.isError () || cell.isNaN ())
{ {
hasValue = true; isError = true;
sum += cell.getValue (); break;
} }
value += cell.getValue ();
} }
} }
} }

View File

@ -2,9 +2,15 @@ package com.bytezone.diskbrowser.visicalc;
interface Value interface Value
{ {
public boolean hasValue (); // public boolean hasValue ();
public double getValue (); public double getValue ();
public String getError (); public String getText ();
public boolean isError ();
public boolean isNaN ();
public void calculate ();
} }