2016-03-04 03:56:28 +00:00
|
|
|
package com.bytezone.diskbrowser.visicalc;
|
2015-06-01 09:35:51 +00:00
|
|
|
|
2016-03-08 09:39:35 +00:00
|
|
|
import java.util.ArrayList;
|
|
|
|
import java.util.List;
|
|
|
|
import java.util.Map;
|
|
|
|
import java.util.TreeMap;
|
2015-06-01 09:35:51 +00:00
|
|
|
import java.util.regex.Matcher;
|
|
|
|
import java.util.regex.Pattern;
|
|
|
|
|
2016-02-24 21:11:14 +00:00
|
|
|
import com.bytezone.diskbrowser.utilities.HexFormatter;
|
2017-03-14 11:28:52 +00:00
|
|
|
import com.bytezone.diskbrowser.visicalc.Cell.CellType;
|
2015-06-01 09:35:51 +00:00
|
|
|
|
2016-03-15 20:06:04 +00:00
|
|
|
public class Sheet
|
2015-06-01 09:35:51 +00:00
|
|
|
{
|
2016-02-04 00:31:44 +00:00
|
|
|
private static final Pattern addressPattern =
|
2016-03-08 09:39:35 +00:00
|
|
|
Pattern.compile ("([AB]?[A-Z])([0-9]{1,3}):");
|
2016-03-15 20:27:47 +00:00
|
|
|
private static final byte END_OF_LINE_TOKEN = (byte) 0x8D;
|
2016-03-16 06:15:39 +00:00
|
|
|
private static final int FORMAT_LENGTH = 3;
|
2015-06-01 09:35:51 +00:00
|
|
|
|
2016-03-15 20:06:04 +00:00
|
|
|
private final Map<Integer, Cell> rowOrderCells = new TreeMap<Integer, Cell> ();
|
|
|
|
private final Map<Integer, Cell> columnOrderCells = new TreeMap<Integer, Cell> ();
|
2016-03-11 02:54:31 +00:00
|
|
|
private final List<String> lines = new ArrayList<String> ();
|
2015-06-01 09:35:51 +00:00
|
|
|
|
2016-03-04 05:27:14 +00:00
|
|
|
private final Map<Integer, Integer> columnWidths = new TreeMap<Integer, Integer> ();
|
2017-03-05 10:42:27 +00:00
|
|
|
private int columnWidth = 9;
|
2016-03-15 20:27:47 +00:00
|
|
|
|
2017-03-05 10:42:27 +00:00
|
|
|
private char globalFormat = ' ';
|
2016-03-15 20:27:47 +00:00
|
|
|
private char recalculation = 'A'; // auto/manual
|
2016-03-15 20:06:04 +00:00
|
|
|
private char recalculationOrder = 'C'; // row/column
|
2016-03-15 20:27:47 +00:00
|
|
|
|
2017-03-05 10:42:27 +00:00
|
|
|
private int minColumn = 9999;
|
|
|
|
private int maxColumn;
|
|
|
|
private int minRow = 9999;
|
|
|
|
private int maxRow;
|
2016-03-04 05:27:14 +00:00
|
|
|
|
2017-03-18 08:33:40 +00:00
|
|
|
int[] functionTotals = new int[Function.functionList.length];
|
|
|
|
|
2015-06-01 09:35:51 +00:00
|
|
|
// Maximum cell = BK254
|
|
|
|
|
|
|
|
//Commands:
|
|
|
|
// /G<address> goto
|
|
|
|
// /B blank the cell
|
|
|
|
// /C clear and home
|
|
|
|
// A-Z label (" to force a label)
|
|
|
|
// 0-9.+-()*/@# value (+ to force a value)
|
|
|
|
|
|
|
|
// /S Storage (ISLDWR)
|
|
|
|
// /SI Storage init
|
|
|
|
// /SS Storage Save
|
|
|
|
// /SL Storage Load
|
|
|
|
// /SD Storage Delete
|
|
|
|
// /SW Storage Write (to cassette)
|
|
|
|
// /SR Storage Read (from cassette)
|
|
|
|
|
|
|
|
// /R Replicate
|
|
|
|
|
|
|
|
// /G Global (CORF)
|
|
|
|
// /GF Global Format (DGILR$*)
|
|
|
|
// /GFI Global Format Integer
|
|
|
|
// /GF$ Global Format Currency
|
2017-03-16 00:27:45 +00:00
|
|
|
// /GC Global Column <width> 3-37
|
|
|
|
// /GR Global Recalculation A/M
|
2016-03-08 09:39:35 +00:00
|
|
|
// /GRA Recalculation Auto
|
2017-03-16 00:27:45 +00:00
|
|
|
// /GO Global Calculation Order C/R
|
2016-03-08 09:39:35 +00:00
|
|
|
// /GOC Calculation Order - Columns first
|
2017-02-26 10:44:10 +00:00
|
|
|
// /GOR Calculation Order - Rows first
|
2015-06-01 09:35:51 +00:00
|
|
|
|
|
|
|
// /T Titles (HVBN)
|
|
|
|
// /TH fix Horizontal Titles
|
|
|
|
// /TV fix Vertical Titles
|
|
|
|
// /TB fix Both Titles
|
|
|
|
// /TN fix Neither
|
|
|
|
|
2017-03-16 00:27:45 +00:00
|
|
|
// /W Window split (HV1SU)
|
2015-06-01 09:35:51 +00:00
|
|
|
// /WV Window Vertical (split on cursor column)
|
|
|
|
// /WH Window Horizontal (split on cursor row)
|
2017-03-16 00:27:45 +00:00
|
|
|
// /W1 Window (return to single window)
|
|
|
|
// /WS Window (synchronised)
|
|
|
|
// /WU Window (unsynchronised)
|
2015-06-01 09:35:51 +00:00
|
|
|
|
2016-02-04 00:31:44 +00:00
|
|
|
/*
|
|
|
|
from: Apple II TextFiles
|
|
|
|
http://www.textfiles.com/apple/
|
|
|
|
|
|
|
|
|
|
|
|
*----------------------*
|
|
|
|
VISICALC COMMAND CHART
|
|
|
|
BY: NIGHT HAWK
|
|
|
|
*----------------------*
|
|
|
|
|
|
|
|
/B SET AN ENTRY TO BLANK
|
|
|
|
|
|
|
|
/C CLEARS THE SHEET, SETTING ALL ENTRIES TO BLANK
|
|
|
|
|
2016-03-14 08:58:54 +00:00
|
|
|
/D DELETE
|
|
|
|
/DR THE ROW
|
|
|
|
/DC COLUMN ON WHICH THE CURSOR LIES
|
2016-02-04 00:31:44 +00:00
|
|
|
|
|
|
|
/E ALLOWS EDITING OF THE ENTRY CONTENTS OF ANY ENTRY POSITION
|
|
|
|
BY REDISPLAYING IT ON THE EDIT LINE. USE <- -> KEYS & ESC.
|
|
|
|
|
2016-03-14 08:58:54 +00:00
|
|
|
/F FORMATS:
|
2016-02-04 00:31:44 +00:00
|
|
|
/FG GENERAL
|
2016-03-14 08:58:54 +00:00
|
|
|
/FI INTEGER
|
|
|
|
/F$ DOLLAR AND CENTS
|
|
|
|
/FL LEFT JUSTIFIED
|
|
|
|
/FR RIGHT JUSTIFIED
|
|
|
|
/F* GRAPH
|
|
|
|
/FD DEFAULT
|
2016-02-04 00:31:44 +00:00
|
|
|
|
|
|
|
/G GLOBAL COMMANDS. THESE APPLY TO THE ENTIRE SHEET OR WINDOW.
|
|
|
|
/GC SETS COLUMN WIDTH
|
|
|
|
/GF SETS THE GLOBAL DEFAULT FORMAT
|
|
|
|
/GO SETS THE ORDER OF RECALCULATION TO BE DOWN THE
|
|
|
|
COLUMNS OR ACROSS THE ROWS
|
|
|
|
/GR SETS RECALCULATION TO BE AUTOMATIC(/GRA) OR MANUAL(/GRM).
|
|
|
|
|
|
|
|
/I INSERTS A ROW(/IR) OR A COLUMN(/IC)
|
|
|
|
/M MOVES AN ENTIRE ROW OR COLUMN TO A NEW POSITION.
|
|
|
|
/P PRINT COMMAND
|
|
|
|
/R REPLICATE COMMAND
|
2016-03-14 08:58:54 +00:00
|
|
|
|
|
|
|
/S STORAGE COMMANDS
|
2016-03-01 22:51:56 +00:00
|
|
|
/SS SAVE
|
2017-02-25 03:56:22 +00:00
|
|
|
/SL LOAD (left/right arrow to scroll through catalog)
|
2016-03-01 22:51:56 +00:00
|
|
|
/SD DELETES SPECIFIED FILE ON DISK
|
2016-02-04 00:31:44 +00:00
|
|
|
/SI INITIALIZE A DISK ON SPECIFIED DRIVE
|
|
|
|
/SQ QUITS VISICALC
|
|
|
|
|
2016-03-14 08:58:54 +00:00
|
|
|
/T
|
|
|
|
/TH SETS A HORIZONTAL TITLE AREA
|
|
|
|
/TV SETS A VERTICAL TITLE AREA
|
|
|
|
/TB SET BOTH A HORIZONTAL & VERTICAL TITLE AREA
|
|
|
|
/TN RESETS THE WINDOWS TO HAVE NO TITLE AREAS
|
|
|
|
|
2016-02-04 00:31:44 +00:00
|
|
|
/V DISPLAYS VISICALC'S VERSION NUMBER ON THE PROMPT LINE
|
|
|
|
/W WINDOW CONTROL
|
|
|
|
/WH HORIZONTAL WINDOW
|
|
|
|
/WV VERTICAL WINDOW
|
|
|
|
/W1 RETURNS SCREEN TO ONE WINDOW
|
|
|
|
/WS SYNCHRONIZED WINDOWS
|
|
|
|
/WU UNSYNCHRONIZED
|
|
|
|
|
|
|
|
/- REPEATING LABEL
|
|
|
|
*/
|
|
|
|
|
2017-02-26 10:44:10 +00:00
|
|
|
// /X!/X>A3:>A7: A3:top-left cell in window, A7:cell to place cursor
|
|
|
|
|
2016-03-06 08:05:32 +00:00
|
|
|
public Sheet (byte[] buffer)
|
2015-06-01 09:35:51 +00:00
|
|
|
{
|
2016-03-04 05:27:14 +00:00
|
|
|
int last = buffer.length;
|
2016-03-14 08:58:54 +00:00
|
|
|
while (buffer[--last] == 0) // ignore trailing zeroes
|
2016-03-04 05:27:14 +00:00
|
|
|
;
|
2015-06-01 09:35:51 +00:00
|
|
|
|
2016-03-04 05:27:14 +00:00
|
|
|
int ptr = 0;
|
2016-03-06 23:52:46 +00:00
|
|
|
while (ptr < last)
|
2015-06-01 09:35:51 +00:00
|
|
|
{
|
2016-03-06 23:52:46 +00:00
|
|
|
int length = getLineLength (buffer, ptr);
|
|
|
|
String line = HexFormatter.getString (buffer, ptr, length);
|
2017-02-25 03:56:22 +00:00
|
|
|
assert !line.isEmpty ();
|
2016-03-06 23:52:46 +00:00
|
|
|
lines.add (line);
|
2017-02-25 03:56:22 +00:00
|
|
|
|
|
|
|
if (line.startsWith ("/"))
|
|
|
|
doFormat (line);
|
|
|
|
else if (line.startsWith (">")) // GOTO cell
|
|
|
|
processLine (line);
|
|
|
|
else
|
|
|
|
System.out.printf ("Error [%s]%n", line);
|
|
|
|
|
2016-03-06 23:52:46 +00:00
|
|
|
ptr += length + 1; // +1 for end-of-line token
|
2015-06-01 09:35:51 +00:00
|
|
|
}
|
|
|
|
|
2017-02-18 09:54:24 +00:00
|
|
|
// might have to keep recalculating until nothing changes??
|
2017-03-15 04:40:18 +00:00
|
|
|
// System.out.println ("\n*********** Calculating\n");
|
2017-03-12 16:47:11 +00:00
|
|
|
calculate (recalculationOrder);
|
2017-03-14 11:28:52 +00:00
|
|
|
// System.out.println ("\n*********** Calculating\n");
|
|
|
|
// calculate (recalculationOrder);
|
2016-03-14 08:58:54 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
private void calculate (char order)
|
|
|
|
{
|
2017-03-14 11:28:52 +00:00
|
|
|
int count = 0;
|
2016-03-15 20:06:04 +00:00
|
|
|
Map<Integer, Cell> cells = order == 'R' ? rowOrderCells : columnOrderCells;
|
|
|
|
for (Cell cell : cells.values ())
|
2017-03-14 11:28:52 +00:00
|
|
|
if (cell.isCellType (CellType.VALUE))
|
|
|
|
{
|
2017-03-15 04:40:18 +00:00
|
|
|
// System.out.printf ("%5d start %s%n", count, cell.getAddressText ());
|
2017-03-14 11:28:52 +00:00
|
|
|
cell.calculate ();
|
2017-03-15 04:40:18 +00:00
|
|
|
// System.out.printf ("%5d stop %s%n", count++, cell.getAddressText ());
|
2017-03-14 11:28:52 +00:00
|
|
|
}
|
2016-03-04 05:27:14 +00:00
|
|
|
}
|
|
|
|
|
2016-03-06 23:52:46 +00:00
|
|
|
private int getLineLength (byte[] buffer, int offset)
|
2016-03-04 05:27:14 +00:00
|
|
|
{
|
2016-03-06 23:52:46 +00:00
|
|
|
int ptr = offset;
|
2017-02-25 03:56:22 +00:00
|
|
|
while (buffer[ptr] != END_OF_LINE_TOKEN)
|
2016-03-04 05:27:14 +00:00
|
|
|
ptr++;
|
2016-03-06 23:52:46 +00:00
|
|
|
return ptr - offset;
|
2015-06-01 09:35:51 +00:00
|
|
|
}
|
|
|
|
|
2016-03-08 09:39:35 +00:00
|
|
|
private void processLine (String line)
|
2015-06-01 09:35:51 +00:00
|
|
|
{
|
2017-02-25 03:56:22 +00:00
|
|
|
Cell currentCell = null;
|
2016-03-08 09:39:35 +00:00
|
|
|
|
2017-02-25 03:56:22 +00:00
|
|
|
Matcher m = addressPattern.matcher (line); // <cell address>:<contents>
|
2016-03-08 09:39:35 +00:00
|
|
|
if (m.find ())
|
2015-06-01 09:35:51 +00:00
|
|
|
{
|
2016-03-08 09:39:35 +00:00
|
|
|
Address address = new Address (m.group (1), m.group (2));
|
2017-03-03 23:41:08 +00:00
|
|
|
currentCell = rowOrderCells.get (address.getRowKey ());
|
2016-03-08 09:39:35 +00:00
|
|
|
|
|
|
|
int pos = line.indexOf (':'); // end of cell address
|
|
|
|
line = line.substring (pos + 1); // remove address from line
|
|
|
|
|
|
|
|
if (currentCell == null)
|
|
|
|
{
|
|
|
|
currentCell = new Cell (this, address);
|
|
|
|
if (!line.startsWith ("/G"))
|
2016-03-15 20:27:47 +00:00
|
|
|
addCell (currentCell);
|
2016-03-08 09:39:35 +00:00
|
|
|
}
|
2015-06-01 09:35:51 +00:00
|
|
|
}
|
2016-03-08 09:39:35 +00:00
|
|
|
else
|
2015-06-01 09:35:51 +00:00
|
|
|
{
|
2016-03-08 09:39:35 +00:00
|
|
|
System.out.printf ("Invalid cell address: %s%n", line);
|
|
|
|
return;
|
2015-06-01 09:35:51 +00:00
|
|
|
}
|
2016-03-08 09:39:35 +00:00
|
|
|
|
|
|
|
assert currentCell != null;
|
|
|
|
|
2016-03-14 20:54:47 +00:00
|
|
|
if (line.startsWith ("/G")) // global column widths
|
2015-06-01 09:35:51 +00:00
|
|
|
{
|
2016-03-08 09:39:35 +00:00
|
|
|
if (line.charAt (2) == 'C' && line.charAt (3) == 'C')
|
|
|
|
{
|
|
|
|
int width = Integer.parseInt (line.substring (4));
|
2017-03-03 23:41:08 +00:00
|
|
|
columnWidths.put (currentCell.getAddress ().getColumn (), width);
|
2016-03-08 09:39:35 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
System.out.printf ("Unknown Global:[%s]%n", line);
|
|
|
|
|
|
|
|
return;
|
2015-06-01 09:35:51 +00:00
|
|
|
}
|
2016-03-08 09:39:35 +00:00
|
|
|
|
2016-03-12 00:48:45 +00:00
|
|
|
// check for formatting commands
|
|
|
|
while (line.startsWith ("/"))
|
2015-06-01 09:35:51 +00:00
|
|
|
{
|
2017-03-05 10:42:27 +00:00
|
|
|
if (line.charAt (1) == '-') // repeating label
|
2016-03-14 20:54:47 +00:00
|
|
|
{
|
2017-02-25 03:56:22 +00:00
|
|
|
currentCell.setFormat (line);
|
|
|
|
line = "";
|
2016-03-14 20:54:47 +00:00
|
|
|
}
|
|
|
|
else
|
2017-02-25 03:56:22 +00:00
|
|
|
{
|
2017-03-05 10:42:27 +00:00
|
|
|
currentCell.setFormat (line.substring (0, FORMAT_LENGTH));
|
2017-02-25 03:56:22 +00:00
|
|
|
line = line.substring (FORMAT_LENGTH);
|
|
|
|
}
|
2015-06-01 09:35:51 +00:00
|
|
|
}
|
|
|
|
|
2017-02-25 03:56:22 +00:00
|
|
|
// if there is anything left it must be an expression
|
2016-03-08 09:39:35 +00:00
|
|
|
if (!line.isEmpty ())
|
2017-03-05 10:42:27 +00:00
|
|
|
currentCell.setValue (line); // expression
|
2016-03-11 21:56:02 +00:00
|
|
|
}
|
|
|
|
|
2016-03-15 20:27:47 +00:00
|
|
|
private void addCell (Cell cell)
|
|
|
|
{
|
2017-03-03 23:41:08 +00:00
|
|
|
rowOrderCells.put (cell.getAddress ().getRowKey (), cell);
|
|
|
|
columnOrderCells.put (cell.getAddress ().getColumnKey (), cell);
|
2016-03-15 20:27:47 +00:00
|
|
|
|
2017-03-05 10:42:27 +00:00
|
|
|
minRow = Math.min (minRow, cell.getAddress ().getRow ());
|
|
|
|
minColumn = Math.min (minColumn, cell.getAddress ().getColumn ());
|
|
|
|
|
|
|
|
maxRow = Math.max (maxRow, cell.getAddress ().getRow ());
|
|
|
|
maxColumn = Math.max (maxColumn, cell.getAddress ().getColumn ());
|
2016-03-15 20:27:47 +00:00
|
|
|
}
|
|
|
|
|
2016-03-11 21:56:02 +00:00
|
|
|
Cell getCell (String addressText)
|
|
|
|
{
|
2016-03-14 08:58:54 +00:00
|
|
|
return getCell (new Address (addressText));
|
2016-03-08 09:39:35 +00:00
|
|
|
}
|
2015-06-01 09:35:51 +00:00
|
|
|
|
2016-03-07 04:37:01 +00:00
|
|
|
Cell getCell (Address address)
|
2015-06-01 09:35:51 +00:00
|
|
|
{
|
2017-03-03 23:41:08 +00:00
|
|
|
Cell cell = rowOrderCells.get (address.getRowKey ());
|
2017-03-03 10:24:23 +00:00
|
|
|
if (cell == null)
|
|
|
|
{
|
|
|
|
cell = new Cell (this, address);
|
|
|
|
addCell (cell);
|
|
|
|
}
|
|
|
|
return cell;
|
|
|
|
}
|
|
|
|
|
|
|
|
boolean cellExists (Address address)
|
|
|
|
{
|
2017-03-03 23:41:08 +00:00
|
|
|
return rowOrderCells.get (address.getRowKey ()) != null;
|
2015-06-01 09:35:51 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
public int size ()
|
|
|
|
{
|
2016-03-15 20:06:04 +00:00
|
|
|
return rowOrderCells.size ();
|
2015-06-01 09:35:51 +00:00
|
|
|
}
|
|
|
|
|
2017-02-25 03:56:22 +00:00
|
|
|
private void doFormat (String line)
|
|
|
|
{
|
|
|
|
switch (line.charAt (1))
|
|
|
|
{
|
|
|
|
case 'G':
|
2017-03-05 10:42:27 +00:00
|
|
|
setGlobal (line);
|
|
|
|
break;
|
|
|
|
case 'W':
|
2017-02-25 03:56:22 +00:00
|
|
|
break;
|
|
|
|
case 'X':
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
System.out.printf ("Skipping [%s]%n", line);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-03-05 10:42:27 +00:00
|
|
|
private void setGlobal (String line)
|
2016-03-11 02:54:31 +00:00
|
|
|
{
|
2017-03-05 10:42:27 +00:00
|
|
|
switch (line.charAt (2))
|
2016-03-11 02:54:31 +00:00
|
|
|
{
|
2017-03-05 10:42:27 +00:00
|
|
|
case 'C':
|
|
|
|
columnWidth = Integer.parseInt (line.substring (3));
|
|
|
|
break;
|
|
|
|
case 'O':
|
|
|
|
recalculationOrder = line.charAt (3);
|
|
|
|
break;
|
|
|
|
case 'R':
|
|
|
|
recalculation = line.charAt (3);
|
|
|
|
break;
|
|
|
|
case 'F':
|
|
|
|
globalFormat = line.charAt (3);
|
|
|
|
break;
|
|
|
|
case 'P':
|
|
|
|
// System.out.printf ("Skipping [%s]%n", line);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
System.out.printf ("Unknown global format [%s]%n", line);
|
|
|
|
break;
|
2016-03-11 02:54:31 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-03-14 22:35:22 +00:00
|
|
|
public String getTextDisplay (boolean debug)
|
2015-06-01 09:35:51 +00:00
|
|
|
{
|
|
|
|
StringBuilder text = new StringBuilder ();
|
2016-03-06 04:41:15 +00:00
|
|
|
String longLine;
|
|
|
|
if (false)
|
|
|
|
longLine = "%+++++++++++++++++++++++++++++++++++++++++++++++++++++++"
|
|
|
|
+ "++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++";
|
|
|
|
else
|
|
|
|
longLine = " "
|
|
|
|
+ " ";
|
2016-03-11 01:52:22 +00:00
|
|
|
String underline = "---------------------------------------------------------"
|
|
|
|
+ "-----------------------------------------------------------------";
|
2017-03-14 11:28:52 +00:00
|
|
|
String left = "";
|
|
|
|
String right = "";
|
|
|
|
if (columnWidth > 2)
|
|
|
|
{
|
|
|
|
left = underline.substring (0, (columnWidth - 2) / 2);
|
|
|
|
right = underline.substring (0, columnWidth - 3 - left.length ()) + "+";
|
|
|
|
}
|
2015-06-01 09:35:51 +00:00
|
|
|
|
2016-03-14 22:55:17 +00:00
|
|
|
int lastRow = 0;
|
2016-03-05 21:53:29 +00:00
|
|
|
int lastColumn = 0;
|
2015-06-01 09:35:51 +00:00
|
|
|
|
2016-03-09 10:38:53 +00:00
|
|
|
StringBuilder heading = new StringBuilder (" ");
|
2017-03-05 10:42:27 +00:00
|
|
|
for (int column = 0; column <= maxColumn; column++)
|
2016-03-09 10:38:53 +00:00
|
|
|
{
|
|
|
|
int width = columnWidth;
|
2016-03-15 20:27:47 +00:00
|
|
|
if (columnWidths.containsKey (column))
|
|
|
|
width = columnWidths.get (column);
|
|
|
|
|
2017-03-15 00:41:45 +00:00
|
|
|
char letter1 = column < 26 ? '-' : column < 52 ? 'A' : 'B';
|
2016-03-15 20:27:47 +00:00
|
|
|
char letter2 = (char) ((column % 26) + 'A');
|
2016-03-09 10:38:53 +00:00
|
|
|
|
|
|
|
if (width == 1)
|
2016-03-14 08:58:54 +00:00
|
|
|
heading.append (letter2);
|
2016-03-10 02:39:23 +00:00
|
|
|
else if (width == 2)
|
2016-03-14 08:58:54 +00:00
|
|
|
heading.append (String.format ("%s%s", letter1, letter2));
|
2016-03-09 10:38:53 +00:00
|
|
|
else
|
2017-03-14 11:28:52 +00:00
|
|
|
{
|
|
|
|
String fmt =
|
|
|
|
String.format ("%s%s%%%d.%ds", letter1, letter2, (width - 2), (width - 2));
|
2016-03-11 01:52:22 +00:00
|
|
|
heading.append (String.format (fmt, underline));
|
2017-03-14 11:28:52 +00:00
|
|
|
// heading.append (left);
|
|
|
|
// heading.append (String.format ("%s%s", letter1, letter2));
|
|
|
|
// heading.append (right);
|
|
|
|
}
|
2016-03-09 10:38:53 +00:00
|
|
|
}
|
2016-03-14 22:35:22 +00:00
|
|
|
|
2017-03-18 08:33:40 +00:00
|
|
|
List<String> counts = new ArrayList<String> ();
|
|
|
|
for (int i = 0; i < functionTotals.length; i++)
|
|
|
|
if (functionTotals[i] > 0)
|
|
|
|
{
|
|
|
|
String name = Function.functionList[i];
|
|
|
|
if (name.endsWith ("("))
|
|
|
|
name = name.substring (0, name.length () - 1);
|
2017-03-18 21:23:44 +00:00
|
|
|
counts.add (String.format ("%-10s%d", name, functionTotals[i]));
|
2017-03-18 08:33:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
while (counts.size () < 18)
|
|
|
|
counts.add ("");
|
|
|
|
|
2017-03-18 21:23:44 +00:00
|
|
|
text.append (String.format ("%-85.85s%n", underline));
|
2017-03-18 08:33:40 +00:00
|
|
|
text.append (String.format ("Global format : %-18s %-18s %-18s %s%n", globalFormat,
|
|
|
|
counts.get (0), counts.get (6), counts.get (12)));
|
|
|
|
text.append (String.format ("Column width : %-2d %-15s %-18s %-18s %s%n",
|
|
|
|
columnWidth, "", counts.get (1), counts.get (7), counts.get (13)));
|
|
|
|
text.append (String.format ("Recalc order : %-18s %-18s %-18s %s%n",
|
|
|
|
recalculationOrder == 'R' ? "Row" : "Column", counts.get (2), counts.get (8),
|
|
|
|
counts.get (14)));
|
|
|
|
text.append (String.format ("Recalculation : %-18s %-18s %-18s %s%n",
|
|
|
|
recalculation == 'A' ? "Automatic" : "Manual", counts.get (3), counts.get (9),
|
|
|
|
counts.get (15)));
|
|
|
|
text.append (String.format ("Cells : %-5d %-11s %-18s %-18s %s%n", size (),
|
|
|
|
"", counts.get (4), counts.get (10), counts.get (16)));
|
2017-03-05 10:42:27 +00:00
|
|
|
|
2017-03-18 21:23:44 +00:00
|
|
|
String rangeText = size () > 0 ? Address.getCellName (minRow + 1, minColumn) + ":"
|
|
|
|
+ Address.getCellName (maxRow + 1, maxColumn) : "";
|
|
|
|
text.append (String.format ("Range : %-18s %-18s %-18s %s%n", rangeText,
|
|
|
|
counts.get (5), counts.get (11), counts.get (17)));
|
|
|
|
text.append (String.format ("%-85.85s%n", underline));
|
2017-03-05 10:42:27 +00:00
|
|
|
|
2016-03-14 22:35:22 +00:00
|
|
|
if (debug)
|
2016-03-14 22:55:17 +00:00
|
|
|
{
|
2016-03-14 22:35:22 +00:00
|
|
|
text.append (heading);
|
2016-03-14 22:55:17 +00:00
|
|
|
text.append ("\n001:");
|
|
|
|
}
|
2016-03-09 10:38:53 +00:00
|
|
|
|
2016-03-15 20:06:04 +00:00
|
|
|
for (Cell cell : rowOrderCells.values ())
|
2015-06-01 09:35:51 +00:00
|
|
|
{
|
2017-02-25 03:56:22 +00:00
|
|
|
Address cellAddress = cell.getAddress ();
|
2017-02-26 10:44:10 +00:00
|
|
|
|
|
|
|
// insert newlines for empty rows
|
2017-03-03 23:41:08 +00:00
|
|
|
while (lastRow < cellAddress.getRow ())
|
2015-06-01 09:35:51 +00:00
|
|
|
{
|
|
|
|
++lastRow;
|
2016-03-05 21:53:29 +00:00
|
|
|
lastColumn = 0;
|
2016-03-14 22:35:22 +00:00
|
|
|
if (debug)
|
|
|
|
text.append (String.format ("%n%03d:", lastRow + 1));
|
|
|
|
else
|
|
|
|
text.append ("\n");
|
2015-06-01 09:35:51 +00:00
|
|
|
}
|
|
|
|
|
2017-02-26 10:44:10 +00:00
|
|
|
// pad out empty columns
|
2017-03-03 23:41:08 +00:00
|
|
|
while (lastColumn < cellAddress.getColumn ())
|
2015-06-01 09:35:51 +00:00
|
|
|
{
|
2016-02-04 00:31:44 +00:00
|
|
|
int width = columnWidth;
|
2016-03-05 21:53:29 +00:00
|
|
|
if (columnWidths.containsKey (lastColumn))
|
|
|
|
width = columnWidths.get (lastColumn);
|
2016-02-04 00:31:44 +00:00
|
|
|
text.append (longLine.substring (0, width));
|
2015-06-01 09:35:51 +00:00
|
|
|
++lastColumn;
|
|
|
|
}
|
|
|
|
|
2016-03-11 22:32:19 +00:00
|
|
|
++lastColumn;
|
|
|
|
|
2016-02-04 00:31:44 +00:00
|
|
|
int colWidth = columnWidth;
|
2017-03-03 23:41:08 +00:00
|
|
|
if (columnWidths.containsKey (cellAddress.getColumn ()))
|
|
|
|
colWidth = columnWidths.get (cellAddress.getColumn ());
|
2016-03-05 21:53:29 +00:00
|
|
|
|
2017-02-27 09:41:05 +00:00
|
|
|
text.append (cell.getText (colWidth, globalFormat));
|
2015-06-01 09:35:51 +00:00
|
|
|
}
|
2017-02-25 03:56:22 +00:00
|
|
|
|
|
|
|
if (debug)
|
|
|
|
{
|
|
|
|
text.append ("\n\n");
|
|
|
|
int last = -1;
|
|
|
|
for (Cell cell : columnOrderCells.values ())
|
|
|
|
{
|
2017-03-03 23:41:08 +00:00
|
|
|
if (last < cell.getAddress ().getColumn ())
|
2017-02-25 03:56:22 +00:00
|
|
|
{
|
2017-03-03 23:41:08 +00:00
|
|
|
String columnName = Address.getCellName (1, cell.getAddress ().getColumn ());
|
2017-02-26 10:44:10 +00:00
|
|
|
columnName = columnName.substring (0, columnName.length () - 1);
|
|
|
|
text.append ("\n *** Column " + columnName
|
|
|
|
+ " ***\n\n");
|
2017-03-03 23:41:08 +00:00
|
|
|
last = cell.getAddress ().getColumn ();
|
2017-02-25 03:56:22 +00:00
|
|
|
}
|
|
|
|
text.append (cell.getDebugText ());
|
|
|
|
text.append ("\n");
|
|
|
|
}
|
2017-03-05 10:42:27 +00:00
|
|
|
|
|
|
|
text.append ("\n");
|
|
|
|
for (String line : lines)
|
|
|
|
{
|
|
|
|
text.append (line);
|
|
|
|
text.append ("\n");
|
|
|
|
}
|
|
|
|
|
|
|
|
if (text.length () > 0)
|
|
|
|
text.deleteCharAt (text.length () - 1);
|
2017-02-25 03:56:22 +00:00
|
|
|
}
|
|
|
|
|
2015-06-01 09:35:51 +00:00
|
|
|
return text.toString ();
|
|
|
|
}
|
2017-03-18 08:33:40 +00:00
|
|
|
|
|
|
|
Function getFunction (Cell cell, String text)
|
|
|
|
{
|
|
|
|
if (text.charAt (0) != '@')
|
|
|
|
{
|
|
|
|
System.out.printf ("Unknown function: [%s]%n", text);
|
|
|
|
return new Error (cell, "@ERROR");
|
|
|
|
}
|
|
|
|
|
2017-03-18 09:21:11 +00:00
|
|
|
String functionName = "";
|
|
|
|
int functionId = -1;
|
2017-03-18 08:33:40 +00:00
|
|
|
for (int i = 0; i < Function.functionList.length; i++)
|
|
|
|
if (text.startsWith (Function.functionList[i]))
|
|
|
|
{
|
2017-03-18 09:21:11 +00:00
|
|
|
functionId = i;
|
2017-03-18 08:33:40 +00:00
|
|
|
functionTotals[i]++;
|
2017-03-18 09:21:11 +00:00
|
|
|
functionName = Function.functionList[i];
|
2017-03-18 08:33:40 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2017-03-18 09:21:11 +00:00
|
|
|
if (functionName.isEmpty ())
|
2017-03-18 08:33:40 +00:00
|
|
|
{
|
2017-03-18 09:21:11 +00:00
|
|
|
System.out.printf ("Unknown function: [%s]%n", text);
|
|
|
|
return new Error (cell, "@ERROR");
|
|
|
|
}
|
|
|
|
|
|
|
|
switch (functionId)
|
|
|
|
{
|
|
|
|
case 0:
|
2017-03-18 08:33:40 +00:00
|
|
|
return new Abs (cell, text);
|
|
|
|
|
2017-03-18 09:21:11 +00:00
|
|
|
case 1:
|
2017-03-18 08:33:40 +00:00
|
|
|
return new Acos (cell, text);
|
|
|
|
|
2017-03-18 09:21:11 +00:00
|
|
|
case 2:
|
2017-03-18 08:33:40 +00:00
|
|
|
return new And (cell, text);
|
|
|
|
|
2017-03-18 09:21:11 +00:00
|
|
|
case 3:
|
2017-03-18 08:33:40 +00:00
|
|
|
return new Asin (cell, text);
|
|
|
|
|
2017-03-18 09:21:11 +00:00
|
|
|
case 4:
|
2017-03-18 08:33:40 +00:00
|
|
|
return new Atan (cell, text);
|
|
|
|
|
2017-03-18 09:21:11 +00:00
|
|
|
case 5:
|
2017-03-18 08:33:40 +00:00
|
|
|
return new Average (cell, text);
|
2017-03-18 09:21:11 +00:00
|
|
|
|
|
|
|
case 6:
|
2017-03-18 08:33:40 +00:00
|
|
|
return new Count (cell, text);
|
|
|
|
|
2017-03-18 09:21:11 +00:00
|
|
|
case 7:
|
2017-03-18 08:33:40 +00:00
|
|
|
return new Choose (cell, text);
|
|
|
|
|
2017-03-18 09:21:11 +00:00
|
|
|
case 8:
|
2017-03-18 08:33:40 +00:00
|
|
|
return new Cos (cell, text);
|
2017-03-18 09:21:11 +00:00
|
|
|
|
|
|
|
case 9:
|
2017-03-18 08:33:40 +00:00
|
|
|
return new Error (cell, text);
|
|
|
|
|
2017-03-18 09:21:11 +00:00
|
|
|
case 10:
|
2017-03-18 08:33:40 +00:00
|
|
|
return new Exp (cell, text);
|
2017-03-18 09:21:11 +00:00
|
|
|
|
|
|
|
case 11:
|
2017-03-18 08:33:40 +00:00
|
|
|
return new False (cell, text);
|
2017-03-18 09:21:11 +00:00
|
|
|
|
|
|
|
case 12:
|
2017-03-18 08:33:40 +00:00
|
|
|
return new If (cell, text);
|
|
|
|
|
2017-03-18 09:21:11 +00:00
|
|
|
case 13:
|
2017-03-18 08:33:40 +00:00
|
|
|
return new Int (cell, text);
|
|
|
|
|
2017-03-18 09:21:11 +00:00
|
|
|
case 14:
|
2017-03-18 08:33:40 +00:00
|
|
|
return new IsError (cell, text);
|
|
|
|
|
2017-03-18 09:21:11 +00:00
|
|
|
case 15:
|
2017-03-18 08:33:40 +00:00
|
|
|
return new IsNa (cell, text);
|
2017-03-18 09:21:11 +00:00
|
|
|
|
|
|
|
case 16:
|
2017-03-18 08:33:40 +00:00
|
|
|
return new Log10 (cell, text);
|
|
|
|
|
2017-03-18 09:21:11 +00:00
|
|
|
case 17:
|
2017-03-18 08:33:40 +00:00
|
|
|
return new Lookup (cell, text);
|
|
|
|
|
2017-03-18 09:21:11 +00:00
|
|
|
case 18:
|
2017-03-18 08:33:40 +00:00
|
|
|
return new Ln (cell, text);
|
2017-03-18 09:21:11 +00:00
|
|
|
|
|
|
|
case 19:
|
2017-03-18 08:33:40 +00:00
|
|
|
return new Min (cell, text);
|
|
|
|
|
2017-03-18 09:21:11 +00:00
|
|
|
case 20:
|
2017-03-18 08:33:40 +00:00
|
|
|
return new Max (cell, text);
|
2017-03-18 09:21:11 +00:00
|
|
|
|
|
|
|
case 21:
|
2017-03-18 08:33:40 +00:00
|
|
|
return new Na (cell, text);
|
|
|
|
|
2017-03-18 09:21:11 +00:00
|
|
|
case 22:
|
2017-03-18 08:33:40 +00:00
|
|
|
return new Npv (cell, text);
|
2017-03-18 09:21:11 +00:00
|
|
|
|
|
|
|
case 23:
|
2017-03-18 08:33:40 +00:00
|
|
|
return new Or (cell, text);
|
2017-03-18 09:21:11 +00:00
|
|
|
|
|
|
|
case 24:
|
2017-03-18 08:33:40 +00:00
|
|
|
return new Pi (cell, text);
|
2017-03-18 09:21:11 +00:00
|
|
|
|
|
|
|
case 25:
|
2017-03-18 08:33:40 +00:00
|
|
|
return new Sin (cell, text);
|
|
|
|
|
2017-03-18 09:21:11 +00:00
|
|
|
case 26:
|
2017-03-18 08:33:40 +00:00
|
|
|
return new Sum (cell, text);
|
|
|
|
|
2017-03-18 09:21:11 +00:00
|
|
|
case 27:
|
2017-03-18 08:33:40 +00:00
|
|
|
return new Sqrt (cell, text);
|
2017-03-18 09:21:11 +00:00
|
|
|
|
|
|
|
case 28:
|
2017-03-18 08:33:40 +00:00
|
|
|
return new Tan (cell, text);
|
|
|
|
|
2017-03-18 09:21:11 +00:00
|
|
|
case 29:
|
2017-03-18 08:33:40 +00:00
|
|
|
return new True (cell, text);
|
|
|
|
|
2017-03-18 09:21:11 +00:00
|
|
|
default:
|
|
|
|
System.out.printf ("Unknown function: [%s]%n", text);
|
|
|
|
return new Error (cell, "@ERROR");
|
|
|
|
}
|
2017-03-18 08:33:40 +00:00
|
|
|
}
|
2015-06-01 09:35:51 +00:00
|
|
|
}
|