Visicalc package

This commit is contained in:
Denis Molony 2016-03-04 14:56:28 +11:00
parent 557066e0f4
commit e017f9121d
5 changed files with 295 additions and 293 deletions

View File

@ -1,6 +1,7 @@
package com.bytezone.diskbrowser.applefile;
import com.bytezone.diskbrowser.utilities.HexFormatter;
import com.bytezone.diskbrowser.visicalc.VisicalcSpreadsheet;
public class VisicalcFile extends AbstractFile
{
@ -23,16 +24,6 @@ public class VisicalcFile extends AbstractFile
text.append ("Cells : " + sheet.size () + "\n\n");
text.append (sheet.getCells ());
if (false)
{
text.append ("\n");
for (String line : sheet.lines)
{
text.append ("\n");
text.append (line);
}
}
return text.toString ();
}

View File

@ -0,0 +1,82 @@
package com.bytezone.diskbrowser.visicalc;
class Address implements Comparable<Address>
{
int row, column;
int sortValue;
String text;
public Address (String column, String row)
{
set (column, row);
}
public Address (int column, int row)
{
assert column <= 64;
assert row <= 255;
this.row = row;
this.column = column;
sortValue = row * 64 + column;
int col1 = column / 26;
int col2 = column % 26;
String col =
col1 > 0 ? (char) ('@' + col1) + ('A' + col2) + "" : (char) ('A' + col2) + "";
text = col + (row + 1);
}
public Address (String address)
{
if (address.charAt (1) < 'A')
set (address.substring (0, 1), address.substring (1));
else
set (address.substring (0, 2), address.substring (2));
}
private void set (String sCol, String sRow)
{
// System.out.printf ("Set: %s, %s%n", sCol, sRow);
if (sCol.length () == 1)
column = sCol.charAt (0) - 'A';
else if (sCol.length () == 2)
column = (sCol.charAt (0) - '@') * 26 + sCol.charAt (1) - 'A';
else
System.out.println ("Bollocks");
try
{
row = Integer.parseInt (sRow) - 1;
sortValue = row * 64 + column;
text = sCol + sRow;
}
catch (NumberFormatException e)
{
System.out.printf ("NFE: %s%n", sRow);
}
}
public Address nextRow ()
{
Address next = new Address (column, row + 1);
return next;
}
public Address nextColumn ()
{
Address next = new Address (column + 1, row);
return next;
}
@Override
public String toString ()
{
return String.format ("%s %d %d %d", text, row, column, sortValue);
}
@Override
public int compareTo (Address o)
{
return sortValue - o.sortValue;
}
}

View File

@ -0,0 +1,65 @@
package com.bytezone.diskbrowser.visicalc;
import java.security.InvalidParameterException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
class Range implements Iterable<Address>
{
Address from, to;
List<Address> range = new ArrayList<Address> ();
public Range (Address from, Address to)
{
this.from = from;
this.to = to;
range.add (from);
if (from.row == to.row)
while (from.compareTo (to) < 0)
{
from = from.nextColumn ();
range.add (from);
}
else if (from.column == to.column)
while (from.compareTo (to) < 0)
{
from = from.nextRow ();
range.add (from);
}
else
throw new InvalidParameterException ();
}
public Range (String[] cells)
{
for (String s : cells)
{
// System.out.println (s);
range.add (new Address (s));
}
}
@Override
public String toString ()
{
if (from == null || to == null)
{
StringBuilder text = new StringBuilder ();
for (Address address : range)
text.append (address.text + ",");
if (text.length () > 0)
text.deleteCharAt (text.length () - 1);
return text.toString ();
}
return String.format (" %s -> %s", from.text, to.text);
}
@Override
public Iterator<Address> iterator ()
{
return range.iterator ();
}
}

View File

@ -0,0 +1,143 @@
package com.bytezone.diskbrowser.visicalc;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
class VisicalcCell implements Comparable<VisicalcCell>
{
private static final Pattern cellContents =
Pattern.compile ("([-+/*]?)(([A-Z]{1,2}[0-9]{1,3})|([0-9.]+)|(@[^-+/*]+))");
final Address address;
private final VisicalcSpreadsheet parent;
private String label;
private double value;
private String formula;
private char format;
private int width;
private int columnWidth;
private char repeatingChar;
private String repeat = "";
private boolean valid;
public VisicalcCell (VisicalcSpreadsheet parent, Address address)
{
this.parent = parent;
this.address = address;
}
public void doCommand (String command)
{
if (command.startsWith ("/"))
{
if (command.charAt (1) == 'F') // format cell
{
format = command.charAt (2);
if (command.length () > 3 && command.charAt (3) == '"')
label = command.substring (4);
}
else if (command.charAt (1) == '-') // repeating label
{
repeatingChar = command.charAt (2);
for (int i = 0; i < 20; i++)
repeat += repeatingChar;
}
else
System.out.println ("Unknown command: " + command);
}
else if (command.startsWith ("\"")) // starts with a quote
label = command.substring (1);
else if (command.matches ("^[0-9.]+$")) // contains only numbers or .
this.value = Float.parseFloat (command);
else
formula = command;
}
public boolean hasValue ()
{
return label == null && repeatingChar == 0;
}
public double getValue ()
{
if (valid || formula == null)
return value;
double result = 0.0;
double interim = 0.0;
Matcher m = cellContents.matcher (formula);
while (m.find ())
{
valid = true;
char operator = m.group (1).isEmpty () ? '+' : m.group (1).charAt (0);
if (m.group (3) != null) // address
interim = parent.getValue (m.group (3));
else if (m.group (4) != null) // constant
try
{
interim = Double.parseDouble (m.group (4));
}
catch (NumberFormatException e)
{
System.out.printf ("NFE: %s%n", m.group (4));
}
else
interim = parent.evaluateFunction (m.group (5)); // function
if (operator == '+')
result += interim;
else if (operator == '-')
result -= interim;
else if (operator == '*')
result *= interim;
else if (operator == '/')
result = interim == 0.0 ? 0 : result / interim;
}
if (valid)
{
value = result;
return result;
}
System.out.println ("?? " + formula);
return value;
}
public String value ()
{
if (label != null)
return label;
if (repeatingChar > 0)
return repeat;
if (formula != null)
if (formula.length () >= 12)
return formula.substring (0, 12);
else
return formula;
return value + "";
}
@Override
public String toString ()
{
String value = repeatingChar == 0 ? label == null
? formula == null ? ", Value: " + this.value : ", Frmla: " + formula
: ", Label: " + label : ", Rpeat: " + repeatingChar;
String format = this.format == 0 ? "" : ", Format: " + this.format;
String width = this.width == 0 ? "" : ", Width: " + this.width;
String columnWidth = this.columnWidth == 0 ? "" : ", Col Width: " + this.columnWidth;
return String.format ("[Cell:%5s%s%s%s%s]", address, format, width, columnWidth,
value);
}
@Override
public int compareTo (VisicalcCell o)
{
return address.compareTo (o.address);
}
}

View File

@ -1,12 +1,10 @@
package com.bytezone.diskbrowser.applefile;
package com.bytezone.diskbrowser.visicalc;
import java.security.InvalidParameterException;
import java.text.DecimalFormat;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import com.bytezone.diskbrowser.applefile.VisicalcSpreadsheet.VisicalcCell;
import com.bytezone.diskbrowser.utilities.HexFormatter;
public class VisicalcSpreadsheet implements Iterable<VisicalcCell>
@ -259,7 +257,7 @@ public class VisicalcSpreadsheet implements Iterable<VisicalcCell>
return ptr;
}
private double evaluateFunction (String function)
double evaluateFunction (String function)
{
if (functions.containsKey (function))
return functions.get (function);
@ -287,7 +285,7 @@ public class VisicalcSpreadsheet implements Iterable<VisicalcCell>
for (Address address : range)
{
VisicalcCell cell = getCell (address);
if (cell != null && cell.hasValue () && cell.value != 0.0)
if (cell != null && cell.hasValue () && cell.getValue () != 0.0)
++count;
}
result = count;
@ -369,7 +367,7 @@ public class VisicalcSpreadsheet implements Iterable<VisicalcCell>
public double getValue (Address address)
{
VisicalcCell cell = sheet.get (address.sortValue);
return cell == null ? 0.0 : cell.value;
return cell == null ? 0.0 : cell.getValue ();
}
public double getValue (String cellName)
@ -454,281 +452,4 @@ public class VisicalcSpreadsheet implements Iterable<VisicalcCell>
}
return text.toString ();
}
class VisicalcCell implements Comparable<VisicalcCell>
{
private final Address address;
private final VisicalcSpreadsheet parent;
private String label;
private double value;
private String formula;
private char format;
private int width;
private int columnWidth;
private char repeatingChar;
private String repeat = "";
private boolean valid;
public VisicalcCell (VisicalcSpreadsheet parent, Address address)
{
this.parent = parent;
this.address = address;
}
public void doCommand (String command)
{
if (command.startsWith ("/"))
{
if (command.charAt (1) == 'F') // format cell
{
format = command.charAt (2);
if (command.length () > 3 && command.charAt (3) == '"')
label = command.substring (4);
}
else if (command.charAt (1) == '-') // repeating label
{
repeatingChar = command.charAt (2);
for (int i = 0; i < 20; i++)
repeat += repeatingChar;
}
else
System.out.println ("Unknown command: " + command);
}
else if (command.startsWith ("\"")) // starts with a quote
label = command.substring (1);
else if (command.matches ("^[0-9.]+$")) // contains only numbers or .
this.value = Float.parseFloat (command);
else
formula = command;
}
public boolean hasValue ()
{
return label == null && repeatingChar == 0;
}
public double getValue ()
{
if (valid || formula == null)
return value;
double result = 0.0;
double interim = 0.0;
Matcher m = cellContents.matcher (formula);
while (m.find ())
{
valid = true;
char operator = m.group (1).isEmpty () ? '+' : m.group (1).charAt (0);
if (m.group (3) != null) // address
interim = parent.getValue (m.group (3));
else if (m.group (4) != null) // constant
try
{
interim = Double.parseDouble (m.group (4));
}
catch (NumberFormatException e)
{
System.out.printf ("NFE: %s%n", m.group (4));
}
else
interim = parent.evaluateFunction (m.group (5)); // function
if (operator == '+')
result += interim;
else if (operator == '-')
result -= interim;
else if (operator == '*')
result *= interim;
else if (operator == '/')
result = interim == 0.0 ? 0 : result / interim;
}
if (valid)
{
value = result;
return result;
}
System.out.println ("?? " + formula);
return value;
}
public String value ()
{
if (label != null)
return label;
if (repeatingChar > 0)
return repeat;
if (formula != null)
if (formula.length () >= 12)
return formula.substring (0, 12);
else
return formula;
return value + "";
}
@Override
public String toString ()
{
String value = repeatingChar == 0 ? label == null
? formula == null ? ", Value: " + this.value : ", Frmla: " + formula
: ", Label: " + label : ", Rpeat: " + repeatingChar;
String format = this.format == 0 ? "" : ", Format: " + this.format;
String width = this.width == 0 ? "" : ", Width: " + this.width;
String columnWidth =
this.columnWidth == 0 ? "" : ", Col Width: " + this.columnWidth;
return String.format ("[Cell:%5s%s%s%s%s]", address, format, width, columnWidth,
value);
}
@Override
public int compareTo (VisicalcCell o)
{
return address.compareTo (o.address);
}
}
class Range implements Iterable<Address>
{
Address from, to;
List<Address> range = new ArrayList<Address> ();
public Range (Address from, Address to)
{
this.from = from;
this.to = to;
range.add (from);
if (from.row == to.row)
while (from.compareTo (to) < 0)
{
from = from.nextColumn ();
range.add (from);
}
else if (from.column == to.column)
while (from.compareTo (to) < 0)
{
from = from.nextRow ();
range.add (from);
}
else
throw new InvalidParameterException ();
}
public Range (String[] cells)
{
for (String s : cells)
{
// System.out.println (s);
range.add (new Address (s));
}
}
@Override
public String toString ()
{
if (from == null || to == null)
{
StringBuilder text = new StringBuilder ();
for (Address address : range)
text.append (address.text + ",");
if (text.length () > 0)
text.deleteCharAt (text.length () - 1);
return text.toString ();
}
return String.format (" %s -> %s", from.text, to.text);
}
@Override
public Iterator<Address> iterator ()
{
return range.iterator ();
}
}
class Address implements Comparable<Address>
{
int row, column;
int sortValue;
String text;
public Address (String column, String row)
{
set (column, row);
}
public Address (int column, int row)
{
assert column <= 64;
assert row <= 255;
this.row = row;
this.column = column;
sortValue = row * 64 + column;
int col1 = column / 26;
int col2 = column % 26;
String col =
col1 > 0 ? (char) ('@' + col1) + ('A' + col2) + "" : (char) ('A' + col2) + "";
text = col + (row + 1);
}
public Address (String address)
{
if (address.charAt (1) < 'A')
set (address.substring (0, 1), address.substring (1));
else
set (address.substring (0, 2), address.substring (2));
}
private void set (String sCol, String sRow)
{
// System.out.printf ("Set: %s, %s%n", sCol, sRow);
if (sCol.length () == 1)
column = sCol.charAt (0) - 'A';
else if (sCol.length () == 2)
column = (sCol.charAt (0) - '@') * 26 + sCol.charAt (1) - 'A';
else
System.out.println ("Bollocks");
try
{
row = Integer.parseInt (sRow) - 1;
sortValue = row * 64 + column;
text = sCol + sRow;
}
catch (NumberFormatException e)
{
System.out.printf ("NFE: %s%n", sRow);
}
}
public Address nextRow ()
{
Address next = new Address (column, row + 1);
return next;
}
public Address nextColumn ()
{
Address next = new Address (column + 1, row);
return next;
}
@Override
public String toString ()
{
return String.format ("%s %d %d %d", text, row, column, sortValue);
}
@Override
public int compareTo (Address o)
{
return sortValue - o.sortValue;
}
}
}