mirror of https://github.com/apache/poi.git
Extended support for cached results of formula cells
git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@694631 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
parent
9b9d63275a
commit
21fa41ec23
|
@ -37,6 +37,7 @@
|
||||||
|
|
||||||
<!-- Don't forget to update status.xml too! -->
|
<!-- Don't forget to update status.xml too! -->
|
||||||
<release version="3.1.1-alpha1" date="2008-??-??">
|
<release version="3.1.1-alpha1" date="2008-??-??">
|
||||||
|
<action dev="POI-DEVELOPERS" type="add">Extended support for cached results of formula cells</action>
|
||||||
<action dev="POI-DEVELOPERS" type="fix">45639 - Fixed AIOOBE due to bad index logic in ColumnInfoRecordsAggregate</action>
|
<action dev="POI-DEVELOPERS" type="fix">45639 - Fixed AIOOBE due to bad index logic in ColumnInfoRecordsAggregate</action>
|
||||||
<action dev="POI-DEVELOPERS" type="fix">Fixed special cases of INDEX function (single column/single row, errors)</action>
|
<action dev="POI-DEVELOPERS" type="fix">Fixed special cases of INDEX function (single column/single row, errors)</action>
|
||||||
<action dev="POI-DEVELOPERS" type="add">45761 - Support for Very Hidden excel sheets in HSSF</action>
|
<action dev="POI-DEVELOPERS" type="add">45761 - Support for Very Hidden excel sheets in HSSF</action>
|
||||||
|
|
|
@ -34,6 +34,7 @@
|
||||||
<!-- Don't forget to update changes.xml too! -->
|
<!-- Don't forget to update changes.xml too! -->
|
||||||
<changes>
|
<changes>
|
||||||
<release version="3.1.1-alpha1" date="2008-??-??">
|
<release version="3.1.1-alpha1" date="2008-??-??">
|
||||||
|
<action dev="POI-DEVELOPERS" type="add">Extended support for cached results of formula cells</action>
|
||||||
<action dev="POI-DEVELOPERS" type="fix">45639 - Fixed AIOOBE due to bad index logic in ColumnInfoRecordsAggregate</action>
|
<action dev="POI-DEVELOPERS" type="fix">45639 - Fixed AIOOBE due to bad index logic in ColumnInfoRecordsAggregate</action>
|
||||||
<action dev="POI-DEVELOPERS" type="fix">Fixed special cases of INDEX function (single column/single row, errors)</action>
|
<action dev="POI-DEVELOPERS" type="fix">Fixed special cases of INDEX function (single column/single row, errors)</action>
|
||||||
<action dev="POI-DEVELOPERS" type="add">45761 - Support for Very Hidden excel sheets in HSSF</action>
|
<action dev="POI-DEVELOPERS" type="add">45761 - Support for Very Hidden excel sheets in HSSF</action>
|
||||||
|
|
|
@ -14,6 +14,7 @@
|
||||||
See the License for the specific language governing permissions and
|
See the License for the specific language governing permissions and
|
||||||
limitations under the License.
|
limitations under the License.
|
||||||
==================================================================== */
|
==================================================================== */
|
||||||
|
|
||||||
package org.apache.poi.hssf.extractor;
|
package org.apache.poi.hssf.extractor;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
@ -49,10 +50,10 @@ import org.apache.poi.poifs.filesystem.POIFSFileSystem;
|
||||||
/**
|
/**
|
||||||
* A text extractor for Excel files, that is based
|
* A text extractor for Excel files, that is based
|
||||||
* on the hssf eventusermodel api.
|
* on the hssf eventusermodel api.
|
||||||
* It will typically use less memory than
|
* It will typically use less memory than
|
||||||
* {@link ExcelExtractor}, but may not provide
|
* {@link ExcelExtractor}, but may not provide
|
||||||
* the same richness of formatting.
|
* the same richness of formatting.
|
||||||
* Returns the textual content of the file, suitable for
|
* Returns the textual content of the file, suitable for
|
||||||
* indexing by something like Lucene, but not really
|
* indexing by something like Lucene, but not really
|
||||||
* intended for display to the user.
|
* intended for display to the user.
|
||||||
* To turn an excel file into a CSV or similar, then see
|
* To turn an excel file into a CSV or similar, then see
|
||||||
|
@ -63,8 +64,8 @@ public class EventBasedExcelExtractor extends POIOLE2TextExtractor {
|
||||||
private POIFSFileSystem fs;
|
private POIFSFileSystem fs;
|
||||||
private boolean includeSheetNames = true;
|
private boolean includeSheetNames = true;
|
||||||
private boolean formulasNotResults = false;
|
private boolean formulasNotResults = false;
|
||||||
|
|
||||||
public EventBasedExcelExtractor(POIFSFileSystem fs) throws IOException {
|
public EventBasedExcelExtractor(POIFSFileSystem fs) {
|
||||||
super(null);
|
super(null);
|
||||||
this.fs = fs;
|
this.fs = fs;
|
||||||
}
|
}
|
||||||
|
@ -98,8 +99,8 @@ public class EventBasedExcelExtractor extends POIOLE2TextExtractor {
|
||||||
public void setFormulasNotResults(boolean formulasNotResults) {
|
public void setFormulasNotResults(boolean formulasNotResults) {
|
||||||
this.formulasNotResults = formulasNotResults;
|
this.formulasNotResults = formulasNotResults;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Retreives the text contents of the file
|
* Retreives the text contents of the file
|
||||||
*/
|
*/
|
||||||
|
@ -107,7 +108,7 @@ public class EventBasedExcelExtractor extends POIOLE2TextExtractor {
|
||||||
String text = null;
|
String text = null;
|
||||||
try {
|
try {
|
||||||
TextListener tl = triggerExtraction();
|
TextListener tl = triggerExtraction();
|
||||||
|
|
||||||
text = tl.text.toString();
|
text = tl.text.toString();
|
||||||
if(! text.endsWith("\n")) {
|
if(! text.endsWith("\n")) {
|
||||||
text = text + "\n";
|
text = text + "\n";
|
||||||
|
@ -115,37 +116,37 @@ public class EventBasedExcelExtractor extends POIOLE2TextExtractor {
|
||||||
} catch(IOException e) {
|
} catch(IOException e) {
|
||||||
throw new RuntimeException(e);
|
throw new RuntimeException(e);
|
||||||
}
|
}
|
||||||
|
|
||||||
return text;
|
return text;
|
||||||
}
|
}
|
||||||
|
|
||||||
private TextListener triggerExtraction() throws IOException {
|
private TextListener triggerExtraction() throws IOException {
|
||||||
TextListener tl = new TextListener();
|
TextListener tl = new TextListener();
|
||||||
FormatTrackingHSSFListener ft = new FormatTrackingHSSFListener(tl);
|
FormatTrackingHSSFListener ft = new FormatTrackingHSSFListener(tl);
|
||||||
tl.ft = ft;
|
tl.ft = ft;
|
||||||
|
|
||||||
// Register and process
|
// Register and process
|
||||||
HSSFEventFactory factory = new HSSFEventFactory();
|
HSSFEventFactory factory = new HSSFEventFactory();
|
||||||
HSSFRequest request = new HSSFRequest();
|
HSSFRequest request = new HSSFRequest();
|
||||||
request.addListenerForAllRecords(ft);
|
request.addListenerForAllRecords(ft);
|
||||||
|
|
||||||
factory.processWorkbookEvents(request, fs);
|
factory.processWorkbookEvents(request, fs);
|
||||||
|
|
||||||
return tl;
|
return tl;
|
||||||
}
|
}
|
||||||
|
|
||||||
private class TextListener implements HSSFListener {
|
private class TextListener implements HSSFListener {
|
||||||
private FormatTrackingHSSFListener ft;
|
private FormatTrackingHSSFListener ft;
|
||||||
private SSTRecord sstRecord;
|
private SSTRecord sstRecord;
|
||||||
|
|
||||||
private List sheetNames = new ArrayList();
|
private List sheetNames = new ArrayList();
|
||||||
private StringBuffer text = new StringBuffer();
|
private StringBuffer text = new StringBuffer();
|
||||||
private int sheetNum = -1;
|
private int sheetNum = -1;
|
||||||
private int rowNum;
|
private int rowNum;
|
||||||
|
|
||||||
private boolean outputNextStringValue = false;
|
private boolean outputNextStringValue = false;
|
||||||
private int nextRow = -1;
|
private int nextRow = -1;
|
||||||
|
|
||||||
public void processRecord(Record record) {
|
public void processRecord(Record record) {
|
||||||
String thisText = null;
|
String thisText = null;
|
||||||
int thisRow = -1;
|
int thisRow = -1;
|
||||||
|
@ -160,7 +161,7 @@ public class EventBasedExcelExtractor extends POIOLE2TextExtractor {
|
||||||
if(bof.getType() == BOFRecord.TYPE_WORKSHEET) {
|
if(bof.getType() == BOFRecord.TYPE_WORKSHEET) {
|
||||||
sheetNum++;
|
sheetNum++;
|
||||||
rowNum = -1;
|
rowNum = -1;
|
||||||
|
|
||||||
if(includeSheetNames) {
|
if(includeSheetNames) {
|
||||||
if(text.length() > 0) text.append("\n");
|
if(text.length() > 0) text.append("\n");
|
||||||
text.append(sheetNames.get(sheetNum));
|
text.append(sheetNames.get(sheetNum));
|
||||||
|
@ -170,60 +171,60 @@ public class EventBasedExcelExtractor extends POIOLE2TextExtractor {
|
||||||
case SSTRecord.sid:
|
case SSTRecord.sid:
|
||||||
sstRecord = (SSTRecord)record;
|
sstRecord = (SSTRecord)record;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case FormulaRecord.sid:
|
case FormulaRecord.sid:
|
||||||
FormulaRecord frec = (FormulaRecord) record;
|
FormulaRecord frec = (FormulaRecord) record;
|
||||||
thisRow = frec.getRow();
|
thisRow = frec.getRow();
|
||||||
|
|
||||||
if(formulasNotResults) {
|
if(formulasNotResults) {
|
||||||
thisText = FormulaParser.toFormulaString(null, frec.getParsedExpression());
|
thisText = FormulaParser.toFormulaString(null, frec.getParsedExpression());
|
||||||
} else {
|
} else {
|
||||||
if(Double.isNaN( frec.getValue() )) {
|
if(frec.hasCachedResultString()) {
|
||||||
// Formula result is a string
|
// Formula result is a string
|
||||||
// This is stored in the next record
|
// This is stored in the next record
|
||||||
outputNextStringValue = true;
|
outputNextStringValue = true;
|
||||||
nextRow = frec.getRow();
|
nextRow = frec.getRow();
|
||||||
} else {
|
} else {
|
||||||
thisText = formatNumberDateCell(frec, frec.getValue());
|
thisText = formatNumberDateCell(frec, frec.getValue());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case StringRecord.sid:
|
case StringRecord.sid:
|
||||||
if(outputNextStringValue) {
|
if(outputNextStringValue) {
|
||||||
// String for formula
|
// String for formula
|
||||||
StringRecord srec = (StringRecord)record;
|
StringRecord srec = (StringRecord)record;
|
||||||
thisText = srec.getString();
|
thisText = srec.getString();
|
||||||
thisRow = nextRow;
|
thisRow = nextRow;
|
||||||
outputNextStringValue = false;
|
outputNextStringValue = false;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case LabelRecord.sid:
|
case LabelRecord.sid:
|
||||||
LabelRecord lrec = (LabelRecord) record;
|
LabelRecord lrec = (LabelRecord) record;
|
||||||
thisRow = lrec.getRow();
|
thisRow = lrec.getRow();
|
||||||
thisText = lrec.getValue();
|
thisText = lrec.getValue();
|
||||||
break;
|
break;
|
||||||
case LabelSSTRecord.sid:
|
case LabelSSTRecord.sid:
|
||||||
LabelSSTRecord lsrec = (LabelSSTRecord) record;
|
LabelSSTRecord lsrec = (LabelSSTRecord) record;
|
||||||
thisRow = lsrec.getRow();
|
thisRow = lsrec.getRow();
|
||||||
if(sstRecord == null) {
|
if(sstRecord == null) {
|
||||||
throw new IllegalStateException("No SST record found");
|
throw new IllegalStateException("No SST record found");
|
||||||
}
|
}
|
||||||
thisText = sstRecord.getString(lsrec.getSSTIndex()).toString();
|
thisText = sstRecord.getString(lsrec.getSSTIndex()).toString();
|
||||||
break;
|
break;
|
||||||
case NoteRecord.sid:
|
case NoteRecord.sid:
|
||||||
NoteRecord nrec = (NoteRecord) record;
|
NoteRecord nrec = (NoteRecord) record;
|
||||||
thisRow = nrec.getRow();
|
thisRow = nrec.getRow();
|
||||||
// TODO: Find object to match nrec.getShapeId()
|
// TODO: Find object to match nrec.getShapeId()
|
||||||
break;
|
break;
|
||||||
case NumberRecord.sid:
|
case NumberRecord.sid:
|
||||||
NumberRecord numrec = (NumberRecord) record;
|
NumberRecord numrec = (NumberRecord) record;
|
||||||
thisRow = numrec.getRow();
|
thisRow = numrec.getRow();
|
||||||
thisText = formatNumberDateCell(numrec, numrec.getValue());
|
thisText = formatNumberDateCell(numrec, numrec.getValue());
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(thisText != null) {
|
if(thisText != null) {
|
||||||
if(thisRow != rowNum) {
|
if(thisRow != rowNum) {
|
||||||
rowNum = thisRow;
|
rowNum = thisRow;
|
||||||
|
@ -235,42 +236,42 @@ public class EventBasedExcelExtractor extends POIOLE2TextExtractor {
|
||||||
text.append(thisText);
|
text.append(thisText);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Formats a number or date cell, be that a real number, or the
|
* Formats a number or date cell, be that a real number, or the
|
||||||
* answer to a formula
|
* answer to a formula
|
||||||
*/
|
*/
|
||||||
private String formatNumberDateCell(CellValueRecordInterface cell, double value) {
|
private String formatNumberDateCell(CellValueRecordInterface cell, double value) {
|
||||||
// Get the built in format, if there is one
|
// Get the built in format, if there is one
|
||||||
int formatIndex = ft.getFormatIndex(cell);
|
int formatIndex = ft.getFormatIndex(cell);
|
||||||
String formatString = ft.getFormatString(cell);
|
String formatString = ft.getFormatString(cell);
|
||||||
|
|
||||||
if(formatString == null) {
|
if(formatString == null) {
|
||||||
return Double.toString(value);
|
return Double.toString(value);
|
||||||
} else {
|
} else {
|
||||||
// Is it a date?
|
// Is it a date?
|
||||||
if(HSSFDateUtil.isADateFormat(formatIndex,formatString) &&
|
if(HSSFDateUtil.isADateFormat(formatIndex,formatString) &&
|
||||||
HSSFDateUtil.isValidExcelDate(value)) {
|
HSSFDateUtil.isValidExcelDate(value)) {
|
||||||
// Java wants M not m for month
|
// Java wants M not m for month
|
||||||
formatString = formatString.replace('m','M');
|
formatString = formatString.replace('m','M');
|
||||||
// Change \- into -, if it's there
|
// Change \- into -, if it's there
|
||||||
formatString = formatString.replaceAll("\\\\-","-");
|
formatString = formatString.replaceAll("\\\\-","-");
|
||||||
|
|
||||||
// Format as a date
|
// Format as a date
|
||||||
Date d = HSSFDateUtil.getJavaDate(value, false);
|
Date d = HSSFDateUtil.getJavaDate(value, false);
|
||||||
DateFormat df = new SimpleDateFormat(formatString);
|
DateFormat df = new SimpleDateFormat(formatString);
|
||||||
return df.format(d);
|
return df.format(d);
|
||||||
} else {
|
} else {
|
||||||
if(formatString == "General") {
|
if(formatString == "General") {
|
||||||
// Some sort of wierd default
|
// Some sort of wierd default
|
||||||
return Double.toString(value);
|
return Double.toString(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Format as a number
|
// Format as a number
|
||||||
DecimalFormat df = new DecimalFormat(formatString);
|
DecimalFormat df = new DecimalFormat(formatString);
|
||||||
return df.format(value);
|
return df.format(value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,16 +14,16 @@
|
||||||
See the License for the specific language governing permissions and
|
See the License for the specific language governing permissions and
|
||||||
limitations under the License.
|
limitations under the License.
|
||||||
==================================================================== */
|
==================================================================== */
|
||||||
|
|
||||||
package org.apache.poi.hssf.extractor;
|
package org.apache.poi.hssf.extractor;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
|
||||||
import org.apache.poi.POIOLE2TextExtractor;
|
import org.apache.poi.POIOLE2TextExtractor;
|
||||||
|
import org.apache.poi.hssf.record.formula.eval.ErrorEval;
|
||||||
import org.apache.poi.hssf.usermodel.HeaderFooter;
|
import org.apache.poi.hssf.usermodel.HeaderFooter;
|
||||||
import org.apache.poi.hssf.usermodel.HSSFCell;
|
import org.apache.poi.hssf.usermodel.HSSFCell;
|
||||||
import org.apache.poi.hssf.usermodel.HSSFComment;
|
import org.apache.poi.hssf.usermodel.HSSFComment;
|
||||||
import org.apache.poi.hssf.usermodel.HSSFFooter;
|
|
||||||
import org.apache.poi.hssf.usermodel.HSSFHeader;
|
|
||||||
import org.apache.poi.hssf.usermodel.HSSFRichTextString;
|
import org.apache.poi.hssf.usermodel.HSSFRichTextString;
|
||||||
import org.apache.poi.hssf.usermodel.HSSFRow;
|
import org.apache.poi.hssf.usermodel.HSSFRow;
|
||||||
import org.apache.poi.hssf.usermodel.HSSFSheet;
|
import org.apache.poi.hssf.usermodel.HSSFSheet;
|
||||||
|
@ -110,40 +110,52 @@ public class ExcelExtractor extends POIOLE2TextExtractor {
|
||||||
int lastCell = row.getLastCellNum();
|
int lastCell = row.getLastCellNum();
|
||||||
for(int k=firstCell;k<lastCell;k++) {
|
for(int k=firstCell;k<lastCell;k++) {
|
||||||
HSSFCell cell = row.getCell(k);
|
HSSFCell cell = row.getCell(k);
|
||||||
boolean outputContents = false;
|
|
||||||
if(cell == null) { continue; }
|
if(cell == null) { continue; }
|
||||||
|
boolean outputContents = true;
|
||||||
|
|
||||||
switch(cell.getCellType()) {
|
switch(cell.getCellType()) {
|
||||||
|
case HSSFCell.CELL_TYPE_BLANK:
|
||||||
|
outputContents = false;
|
||||||
|
break;
|
||||||
case HSSFCell.CELL_TYPE_STRING:
|
case HSSFCell.CELL_TYPE_STRING:
|
||||||
text.append(cell.getRichStringCellValue().getString());
|
text.append(cell.getRichStringCellValue().getString());
|
||||||
outputContents = true;
|
|
||||||
break;
|
break;
|
||||||
case HSSFCell.CELL_TYPE_NUMERIC:
|
case HSSFCell.CELL_TYPE_NUMERIC:
|
||||||
// Note - we don't apply any formatting!
|
// Note - we don't apply any formatting!
|
||||||
text.append(cell.getNumericCellValue());
|
text.append(cell.getNumericCellValue());
|
||||||
outputContents = true;
|
|
||||||
break;
|
break;
|
||||||
case HSSFCell.CELL_TYPE_BOOLEAN:
|
case HSSFCell.CELL_TYPE_BOOLEAN:
|
||||||
text.append(cell.getBooleanCellValue());
|
text.append(cell.getBooleanCellValue());
|
||||||
outputContents = true;
|
break;
|
||||||
|
case HSSFCell.CELL_TYPE_ERROR:
|
||||||
|
text.append(ErrorEval.getText(cell.getErrorCellValue()));
|
||||||
break;
|
break;
|
||||||
case HSSFCell.CELL_TYPE_FORMULA:
|
case HSSFCell.CELL_TYPE_FORMULA:
|
||||||
if(formulasNotResults) {
|
if(formulasNotResults) {
|
||||||
text.append(cell.getCellFormula());
|
text.append(cell.getCellFormula());
|
||||||
} else {
|
} else {
|
||||||
// Try it as a string, if not as a number
|
switch(cell.getCachedFormulaResultType()) {
|
||||||
HSSFRichTextString str =
|
case HSSFCell.CELL_TYPE_STRING:
|
||||||
cell.getRichStringCellValue();
|
HSSFRichTextString str = cell.getRichStringCellValue();
|
||||||
if(str != null && str.length() > 0) {
|
if(str != null && str.length() > 0) {
|
||||||
text.append(str.toString());
|
text.append(str.toString());
|
||||||
} else {
|
}
|
||||||
// Try and treat it as a number
|
break;
|
||||||
double val = cell.getNumericCellValue();
|
case HSSFCell.CELL_TYPE_NUMERIC:
|
||||||
text.append(val);
|
text.append(cell.getNumericCellValue());
|
||||||
|
break;
|
||||||
|
case HSSFCell.CELL_TYPE_BOOLEAN:
|
||||||
|
text.append(cell.getBooleanCellValue());
|
||||||
|
break;
|
||||||
|
case HSSFCell.CELL_TYPE_ERROR:
|
||||||
|
text.append(ErrorEval.getText(cell.getErrorCellValue()));
|
||||||
|
break;
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
outputContents = true;
|
|
||||||
break;
|
break;
|
||||||
|
default:
|
||||||
|
throw new RuntimeException("Unexpected cell type (" + cell.getCellType() + ")");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Output the comment, if requested and exists
|
// Output the comment, if requested and exists
|
||||||
|
|
|
@ -18,6 +18,8 @@
|
||||||
package org.apache.poi.hssf.record;
|
package org.apache.poi.hssf.record;
|
||||||
|
|
||||||
import org.apache.poi.hssf.record.formula.Ptg;
|
import org.apache.poi.hssf.record.formula.Ptg;
|
||||||
|
import org.apache.poi.hssf.record.formula.eval.ErrorEval;
|
||||||
|
import org.apache.poi.hssf.usermodel.HSSFCell;
|
||||||
import org.apache.poi.util.BitField;
|
import org.apache.poi.util.BitField;
|
||||||
import org.apache.poi.util.BitFieldFactory;
|
import org.apache.poi.util.BitFieldFactory;
|
||||||
import org.apache.poi.util.HexDump;
|
import org.apache.poi.util.HexDump;
|
||||||
|
@ -32,264 +34,430 @@ import org.apache.poi.util.LittleEndian;
|
||||||
*/
|
*/
|
||||||
public final class FormulaRecord extends Record implements CellValueRecordInterface {
|
public final class FormulaRecord extends Record implements CellValueRecordInterface {
|
||||||
|
|
||||||
public static final short sid = 0x0006; // docs say 406...because of a bug Microsoft support site article #Q184647)
|
public static final short sid = 0x0006; // docs say 406...because of a bug Microsoft support site article #Q184647)
|
||||||
private static int FIXED_SIZE = 22;
|
private static int FIXED_SIZE = 22;
|
||||||
|
|
||||||
private static final BitField alwaysCalc = BitFieldFactory.getInstance(0x0001);
|
private static final BitField alwaysCalc = BitFieldFactory.getInstance(0x0001);
|
||||||
private static final BitField calcOnLoad = BitFieldFactory.getInstance(0x0002);
|
private static final BitField calcOnLoad = BitFieldFactory.getInstance(0x0002);
|
||||||
private static final BitField sharedFormula = BitFieldFactory.getInstance(0x0008);
|
private static final BitField sharedFormula = BitFieldFactory.getInstance(0x0008);
|
||||||
|
|
||||||
private int field_1_row;
|
/**
|
||||||
private short field_2_column;
|
* Manages the cached formula result values of other types besides numeric.
|
||||||
private short field_3_xf;
|
* Excel encodes the same 8 bytes that would be field_4_value with various NaN
|
||||||
private double field_4_value;
|
* values that are decoded/encoded by this class.
|
||||||
private short field_5_options;
|
*/
|
||||||
private int field_6_zero;
|
private static final class SpecialCachedValue {
|
||||||
private Ptg[] field_8_parsed_expr;
|
/** deliberately chosen by Excel in order to encode other values within Double NaNs */
|
||||||
|
private static final long BIT_MARKER = 0xFFFF000000000000L;
|
||||||
|
private static final int VARIABLE_DATA_LENGTH = 6;
|
||||||
|
private static final int DATA_INDEX = 2;
|
||||||
|
|
||||||
/**
|
public static final int STRING = 0;
|
||||||
* Since the NaN support seems sketchy (different constants) we'll store and spit it out directly
|
public static final int BOOLEAN = 1;
|
||||||
*/
|
public static final int ERROR_CODE = 2;
|
||||||
private byte[] value_data;
|
public static final int EMPTY = 3;
|
||||||
|
|
||||||
/** Creates new FormulaRecord */
|
private final byte[] _variableData;
|
||||||
|
|
||||||
public FormulaRecord() {
|
private SpecialCachedValue(byte[] data) {
|
||||||
field_8_parsed_expr = Ptg.EMPTY_PTG_ARRAY;
|
_variableData = data;
|
||||||
}
|
}
|
||||||
|
public int getTypeCode() {
|
||||||
|
return _variableData[0];
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructs a Formula record and sets its fields appropriately.
|
* @return <code>null</code> if the double value encoded by <tt>valueLongBits</tt>
|
||||||
* Note - id must be 0x06 (NOT 0x406 see MSKB #Q184647 for an
|
* is a normal (non NaN) double value.
|
||||||
* "explanation of this bug in the documentation) or an exception
|
*/
|
||||||
* will be throw upon validation
|
public static SpecialCachedValue create(long valueLongBits) {
|
||||||
*
|
if ((BIT_MARKER & valueLongBits) != BIT_MARKER) {
|
||||||
* @param in the RecordInputstream to read the record from
|
return null;
|
||||||
*/
|
}
|
||||||
|
|
||||||
public FormulaRecord(RecordInputStream in) {
|
byte[] result = new byte[VARIABLE_DATA_LENGTH];
|
||||||
super(in);
|
long x = valueLongBits;
|
||||||
}
|
for (int i=0; i<VARIABLE_DATA_LENGTH; i++) {
|
||||||
|
result[i] = (byte) x;
|
||||||
|
x >>= 8;
|
||||||
|
}
|
||||||
|
switch (result[0]) {
|
||||||
|
case STRING:
|
||||||
|
case BOOLEAN:
|
||||||
|
case ERROR_CODE:
|
||||||
|
case EMPTY:
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new RecordFormatException("Bad special value code (" + result[0] + ")");
|
||||||
|
}
|
||||||
|
return new SpecialCachedValue(result);
|
||||||
|
}
|
||||||
|
public void serialize(byte[] data, int offset) {
|
||||||
|
System.arraycopy(_variableData, 0, data, offset, VARIABLE_DATA_LENGTH);
|
||||||
|
LittleEndian.putUShort(data, offset+VARIABLE_DATA_LENGTH, 0xFFFF);
|
||||||
|
}
|
||||||
|
public String formatDebugString() {
|
||||||
|
return formatValue() + ' ' + HexDump.toHex(_variableData);
|
||||||
|
}
|
||||||
|
private String formatValue() {
|
||||||
|
int typeCode = getTypeCode();
|
||||||
|
switch (typeCode) {
|
||||||
|
case STRING: return "<string>";
|
||||||
|
case BOOLEAN: return getDataValue() == 0 ? "FALSE" : "TRUE";
|
||||||
|
case ERROR_CODE: return ErrorEval.getText(getDataValue());
|
||||||
|
case EMPTY: return "<empty>";
|
||||||
|
}
|
||||||
|
return "#error(type=" + typeCode + ")#";
|
||||||
|
}
|
||||||
|
private int getDataValue() {
|
||||||
|
return _variableData[DATA_INDEX];
|
||||||
|
}
|
||||||
|
public static SpecialCachedValue createCachedEmptyValue() {
|
||||||
|
return create(EMPTY, 0);
|
||||||
|
}
|
||||||
|
public static SpecialCachedValue createForString() {
|
||||||
|
return create(STRING, 0);
|
||||||
|
}
|
||||||
|
public static SpecialCachedValue createCachedBoolean(boolean b) {
|
||||||
|
return create(BOOLEAN, b ? 0 : 1);
|
||||||
|
}
|
||||||
|
public static SpecialCachedValue createCachedErrorCode(int errorCode) {
|
||||||
|
return create(ERROR_CODE, errorCode);
|
||||||
|
}
|
||||||
|
private static SpecialCachedValue create(int code, int data) {
|
||||||
|
byte[] vd = {
|
||||||
|
(byte) code,
|
||||||
|
0,
|
||||||
|
(byte) data,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
};
|
||||||
|
return new SpecialCachedValue(vd);
|
||||||
|
}
|
||||||
|
public String toString() {
|
||||||
|
StringBuffer sb = new StringBuffer(64);
|
||||||
|
sb.append(getClass().getName());
|
||||||
|
sb.append('[').append(formatValue()).append(']');
|
||||||
|
return sb.toString();
|
||||||
|
}
|
||||||
|
public int getValueType() {
|
||||||
|
int typeCode = getTypeCode();
|
||||||
|
switch (typeCode) {
|
||||||
|
case STRING: return HSSFCell.CELL_TYPE_STRING;
|
||||||
|
case BOOLEAN: return HSSFCell.CELL_TYPE_BOOLEAN;
|
||||||
|
case ERROR_CODE: return HSSFCell.CELL_TYPE_ERROR;
|
||||||
|
case EMPTY: return HSSFCell.CELL_TYPE_STRING; // is this correct?
|
||||||
|
}
|
||||||
|
throw new IllegalStateException("Unexpected type id (" + typeCode + ")");
|
||||||
|
}
|
||||||
|
public boolean getBooleanValue() {
|
||||||
|
if (getTypeCode() != BOOLEAN) {
|
||||||
|
throw new IllegalStateException("Not a boolean cached value - " + formatValue());
|
||||||
|
}
|
||||||
|
return getDataValue() != 0;
|
||||||
|
}
|
||||||
|
public int getErrorValue() {
|
||||||
|
if (getTypeCode() != ERROR_CODE) {
|
||||||
|
throw new IllegalStateException("Not an error cached value - " + formatValue());
|
||||||
|
}
|
||||||
|
return getDataValue();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
protected void fillFields(RecordInputStream in) {
|
|
||||||
field_1_row = in.readUShort();
|
|
||||||
field_2_column = in.readShort();
|
|
||||||
field_3_xf = in.readShort();
|
|
||||||
field_4_value = in.readDouble();
|
|
||||||
field_5_options = in.readShort();
|
|
||||||
|
|
||||||
if (Double.isNaN(field_4_value)) {
|
|
||||||
value_data = in.getNANData();
|
|
||||||
}
|
|
||||||
|
|
||||||
field_6_zero = in.readInt();
|
private int field_1_row;
|
||||||
int field_7_expression_len = in.readShort(); // this length does not include any extra array data
|
private short field_2_column;
|
||||||
field_8_parsed_expr = Ptg.readTokens(field_7_expression_len, in);
|
private short field_3_xf;
|
||||||
if (in.remaining() == 10) {
|
private double field_4_value;
|
||||||
// TODO - this seems to occur when IntersectionPtg is present
|
private short field_5_options;
|
||||||
// 10 extra bytes are just 0x01 and 0x00
|
private int field_6_zero;
|
||||||
// This causes POI stderr: "WARN. Unread 10 bytes of record 0x6"
|
private Ptg[] field_8_parsed_expr;
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setRow(int row) {
|
/**
|
||||||
field_1_row = row;
|
* Since the NaN support seems sketchy (different constants) we'll store and spit it out directly
|
||||||
}
|
*/
|
||||||
|
private SpecialCachedValue specialCachedValue;
|
||||||
|
|
||||||
public void setColumn(short column) {
|
/** Creates new FormulaRecord */
|
||||||
field_2_column = column;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setXFIndex(short xf) {
|
public FormulaRecord() {
|
||||||
field_3_xf = xf;
|
field_8_parsed_expr = Ptg.EMPTY_PTG_ARRAY;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* set the calculated value of the formula
|
* Constructs a Formula record and sets its fields appropriately.
|
||||||
*
|
* Note - id must be 0x06 (NOT 0x406 see MSKB #Q184647 for an
|
||||||
* @param value calculated value
|
* "explanation of this bug in the documentation) or an exception
|
||||||
*/
|
* will be throw upon validation
|
||||||
public void setValue(double value) {
|
*
|
||||||
field_4_value = value;
|
* @param in the RecordInputstream to read the record from
|
||||||
}
|
*/
|
||||||
|
|
||||||
/**
|
public FormulaRecord(RecordInputStream in) {
|
||||||
* set the option flags
|
super(in);
|
||||||
*
|
}
|
||||||
* @param options bitmask
|
|
||||||
*/
|
|
||||||
public void setOptions(short options) {
|
|
||||||
field_5_options = options;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getRow() {
|
protected void fillFields(RecordInputStream in) {
|
||||||
return field_1_row;
|
field_1_row = in.readUShort();
|
||||||
}
|
field_2_column = in.readShort();
|
||||||
|
field_3_xf = in.readShort();
|
||||||
|
long valueLongBits = in.readLong();
|
||||||
|
field_5_options = in.readShort();
|
||||||
|
specialCachedValue = SpecialCachedValue.create(valueLongBits);
|
||||||
|
if (specialCachedValue == null) {
|
||||||
|
field_4_value = Double.longBitsToDouble(valueLongBits);
|
||||||
|
}
|
||||||
|
|
||||||
public short getColumn() {
|
field_6_zero = in.readInt();
|
||||||
return field_2_column;
|
int field_7_expression_len = in.readShort(); // this length does not include any extra array data
|
||||||
}
|
field_8_parsed_expr = Ptg.readTokens(field_7_expression_len, in);
|
||||||
|
if (in.remaining() == 10) {
|
||||||
|
// TODO - this seems to occur when IntersectionPtg is present
|
||||||
|
// 10 extra bytes are just 0x01 and 0x00
|
||||||
|
// This causes POI stderr: "WARN. Unread 10 bytes of record 0x6"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public short getXFIndex() {
|
|
||||||
return field_3_xf;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
public void setRow(int row) {
|
||||||
* get the calculated value of the formula
|
field_1_row = row;
|
||||||
*
|
}
|
||||||
* @return calculated value
|
|
||||||
*/
|
|
||||||
public double getValue() {
|
|
||||||
return field_4_value;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
public void setColumn(short column) {
|
||||||
* get the option flags
|
field_2_column = column;
|
||||||
*
|
}
|
||||||
* @return bitmask
|
|
||||||
*/
|
|
||||||
public short getOptions() {
|
|
||||||
return field_5_options;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isSharedFormula() {
|
public void setXFIndex(short xf) {
|
||||||
return sharedFormula.isSet(field_5_options);
|
field_3_xf = xf;
|
||||||
}
|
}
|
||||||
public void setSharedFormula(boolean flag) {
|
|
||||||
field_5_options =
|
|
||||||
sharedFormula.setShortBoolean(field_5_options, flag);
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isAlwaysCalc() {
|
/**
|
||||||
return alwaysCalc.isSet(field_5_options);
|
* set the calculated value of the formula
|
||||||
}
|
*
|
||||||
public void setAlwaysCalc(boolean flag) {
|
* @param value calculated value
|
||||||
field_5_options =
|
*/
|
||||||
alwaysCalc.setShortBoolean(field_5_options, flag);
|
public void setValue(double value) {
|
||||||
}
|
field_4_value = value;
|
||||||
|
specialCachedValue = null;
|
||||||
|
}
|
||||||
|
|
||||||
public boolean isCalcOnLoad() {
|
public void setCachedResultTypeEmptyString() {
|
||||||
return calcOnLoad.isSet(field_5_options);
|
specialCachedValue = SpecialCachedValue.createCachedEmptyValue();
|
||||||
}
|
}
|
||||||
public void setCalcOnLoad(boolean flag) {
|
public void setCachedResultTypeString() {
|
||||||
field_5_options =
|
specialCachedValue = SpecialCachedValue.createForString();
|
||||||
calcOnLoad.setShortBoolean(field_5_options, flag);
|
}
|
||||||
}
|
public void setCachedResultErrorCode(int errorCode) {
|
||||||
|
specialCachedValue = SpecialCachedValue.createCachedErrorCode(errorCode);
|
||||||
|
}
|
||||||
|
public void setCachedResultBoolean(boolean value) {
|
||||||
|
specialCachedValue = SpecialCachedValue.createCachedBoolean(value);
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* @return <code>true</code> if this {@link FormulaRecord} is followed by a
|
||||||
|
* {@link StringRecord} representing the cached text result of the formula
|
||||||
|
* evaluation.
|
||||||
|
*/
|
||||||
|
public boolean hasCachedResultString() {
|
||||||
|
if (specialCachedValue == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return specialCachedValue.getTypeCode() == SpecialCachedValue.STRING;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
public int getCachedResultType() {
|
||||||
* @return the formula tokens. never <code>null</code>
|
if (specialCachedValue == null) {
|
||||||
*/
|
return HSSFCell.CELL_TYPE_NUMERIC;
|
||||||
public Ptg[] getParsedExpression() {
|
}
|
||||||
return (Ptg[]) field_8_parsed_expr.clone();
|
return specialCachedValue.getValueType();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setParsedExpression(Ptg[] ptgs) {
|
public boolean getCachedBooleanValue() {
|
||||||
field_8_parsed_expr = ptgs;
|
return specialCachedValue.getBooleanValue();
|
||||||
}
|
}
|
||||||
|
public int getCachedErrorValue() {
|
||||||
|
return specialCachedValue.getErrorValue();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* called by constructor, should throw runtime exception in the event of a
|
|
||||||
* record passed with a differing ID.
|
|
||||||
*
|
|
||||||
* @param id alleged id for this record
|
|
||||||
*/
|
|
||||||
protected void validateSid(short id) {
|
|
||||||
if (id != sid) {
|
|
||||||
throw new RecordFormatException("NOT A FORMULA RECORD");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public short getSid() {
|
/**
|
||||||
return sid;
|
* set the option flags
|
||||||
}
|
*
|
||||||
|
* @param options bitmask
|
||||||
|
*/
|
||||||
|
public void setOptions(short options) {
|
||||||
|
field_5_options = options;
|
||||||
|
}
|
||||||
|
|
||||||
private int getDataSize() {
|
public int getRow() {
|
||||||
return FIXED_SIZE + Ptg.getEncodedSize(field_8_parsed_expr);
|
return field_1_row;
|
||||||
}
|
}
|
||||||
public int serialize(int offset, byte [] data) {
|
|
||||||
|
|
||||||
int dataSize = getDataSize();
|
public short getColumn() {
|
||||||
|
return field_2_column;
|
||||||
|
}
|
||||||
|
|
||||||
LittleEndian.putShort(data, 0 + offset, sid);
|
public short getXFIndex() {
|
||||||
LittleEndian.putUShort(data, 2 + offset, dataSize);
|
return field_3_xf;
|
||||||
LittleEndian.putUShort(data, 4 + offset, getRow());
|
}
|
||||||
LittleEndian.putShort(data, 6 + offset, getColumn());
|
|
||||||
LittleEndian.putShort(data, 8 + offset, getXFIndex());
|
|
||||||
|
|
||||||
//only reserialize if the value is still NaN and we have old nan data
|
/**
|
||||||
if (Double.isNaN(getValue()) && value_data != null) {
|
* get the calculated value of the formula
|
||||||
System.arraycopy(value_data,0,data,10 + offset,value_data.length);
|
*
|
||||||
} else {
|
* @return calculated value
|
||||||
LittleEndian.putDouble(data, 10 + offset, field_4_value);
|
*/
|
||||||
}
|
public double getValue() {
|
||||||
|
return field_4_value;
|
||||||
|
}
|
||||||
|
|
||||||
LittleEndian.putShort(data, 18 + offset, getOptions());
|
/**
|
||||||
|
* get the option flags
|
||||||
|
*
|
||||||
|
* @return bitmask
|
||||||
|
*/
|
||||||
|
public short getOptions() {
|
||||||
|
return field_5_options;
|
||||||
|
}
|
||||||
|
|
||||||
//when writing the chn field (offset 20), it's supposed to be 0 but ignored on read
|
public boolean isSharedFormula() {
|
||||||
//Microsoft Excel Developer's Kit Page 318
|
return sharedFormula.isSet(field_5_options);
|
||||||
LittleEndian.putInt(data, 20 + offset, 0);
|
}
|
||||||
int formulaTokensSize = Ptg.getEncodedSizeWithoutArrayData(field_8_parsed_expr);
|
public void setSharedFormula(boolean flag) {
|
||||||
LittleEndian.putUShort(data, 24 + offset, formulaTokensSize);
|
field_5_options =
|
||||||
Ptg.serializePtgs(field_8_parsed_expr, data, 26+offset);
|
sharedFormula.setShortBoolean(field_5_options, flag);
|
||||||
return 4 + dataSize;
|
}
|
||||||
}
|
|
||||||
|
|
||||||
public int getRecordSize() {
|
public boolean isAlwaysCalc() {
|
||||||
return 4 + getDataSize();
|
return alwaysCalc.isSet(field_5_options);
|
||||||
}
|
}
|
||||||
|
public void setAlwaysCalc(boolean flag) {
|
||||||
|
field_5_options =
|
||||||
|
alwaysCalc.setShortBoolean(field_5_options, flag);
|
||||||
|
}
|
||||||
|
|
||||||
public boolean isInValueSection() {
|
public boolean isCalcOnLoad() {
|
||||||
return true;
|
return calcOnLoad.isSet(field_5_options);
|
||||||
}
|
}
|
||||||
|
public void setCalcOnLoad(boolean flag) {
|
||||||
|
field_5_options =
|
||||||
|
calcOnLoad.setShortBoolean(field_5_options, flag);
|
||||||
|
}
|
||||||
|
|
||||||
public boolean isValue() {
|
/**
|
||||||
return true;
|
* @return the formula tokens. never <code>null</code>
|
||||||
}
|
*/
|
||||||
|
public Ptg[] getParsedExpression() {
|
||||||
|
return (Ptg[]) field_8_parsed_expr.clone();
|
||||||
|
}
|
||||||
|
|
||||||
public String toString() {
|
public void setParsedExpression(Ptg[] ptgs) {
|
||||||
|
field_8_parsed_expr = ptgs;
|
||||||
|
}
|
||||||
|
|
||||||
StringBuffer sb = new StringBuffer();
|
/**
|
||||||
sb.append("[FORMULA]\n");
|
* called by constructor, should throw runtime exception in the event of a
|
||||||
sb.append(" .row = ").append(HexDump.shortToHex(getRow())).append("\n");
|
* record passed with a differing ID.
|
||||||
sb.append(" .column = ").append(HexDump.shortToHex(getColumn())).append("\n");
|
*
|
||||||
sb.append(" .xf = ").append(HexDump.shortToHex(getXFIndex())).append("\n");
|
* @param id alleged id for this record
|
||||||
sb.append(" .value = ");
|
*/
|
||||||
if (Double.isNaN(this.getValue()) && value_data != null) {
|
protected void validateSid(short id) {
|
||||||
sb.append("(NaN)").append(HexDump.dump(value_data,0,0)).append("\n");
|
if (id != sid) {
|
||||||
} else {
|
throw new RecordFormatException("NOT A FORMULA RECORD");
|
||||||
sb.append(getValue()).append("\n");
|
}
|
||||||
}
|
}
|
||||||
sb.append(" .options = ").append(HexDump.shortToHex(getOptions())).append("\n");
|
|
||||||
sb.append(" .alwaysCalc= ").append(alwaysCalc.isSet(getOptions())).append("\n");
|
|
||||||
sb.append(" .calcOnLoad= ").append(calcOnLoad.isSet(getOptions())).append("\n");
|
|
||||||
sb.append(" .shared = ").append(sharedFormula.isSet(getOptions())).append("\n");
|
|
||||||
sb.append(" .zero = ").append(HexDump.intToHex(field_6_zero)).append("\n");
|
|
||||||
|
|
||||||
for (int k = 0; k < field_8_parsed_expr.length; k++ ) {
|
public short getSid() {
|
||||||
sb.append(" Ptg[").append(k).append("]=");
|
return sid;
|
||||||
Ptg ptg = field_8_parsed_expr[k];
|
}
|
||||||
sb.append(ptg.toString()).append(ptg.getRVAType()).append("\n");
|
|
||||||
}
|
|
||||||
sb.append("[/FORMULA]\n");
|
|
||||||
return sb.toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
public Object clone() {
|
private int getDataSize() {
|
||||||
FormulaRecord rec = new FormulaRecord();
|
return FIXED_SIZE + Ptg.getEncodedSize(field_8_parsed_expr);
|
||||||
rec.field_1_row = field_1_row;
|
}
|
||||||
rec.field_2_column = field_2_column;
|
public int serialize(int offset, byte [] data) {
|
||||||
rec.field_3_xf = field_3_xf;
|
|
||||||
rec.field_4_value = field_4_value;
|
int dataSize = getDataSize();
|
||||||
rec.field_5_options = field_5_options;
|
|
||||||
rec.field_6_zero = field_6_zero;
|
LittleEndian.putShort(data, 0 + offset, sid);
|
||||||
int nTokens = field_8_parsed_expr.length;
|
LittleEndian.putUShort(data, 2 + offset, dataSize);
|
||||||
Ptg[] ptgs = new Ptg[nTokens];
|
LittleEndian.putUShort(data, 4 + offset, getRow());
|
||||||
for (int i=0; i< nTokens; i++) {
|
LittleEndian.putShort(data, 6 + offset, getColumn());
|
||||||
ptgs[i] = field_8_parsed_expr[i].copy();
|
LittleEndian.putShort(data, 8 + offset, getXFIndex());
|
||||||
}
|
|
||||||
rec.field_8_parsed_expr = ptgs;
|
if (specialCachedValue == null) {
|
||||||
rec.value_data = value_data;
|
LittleEndian.putDouble(data, 10 + offset, field_4_value);
|
||||||
return rec;
|
} else {
|
||||||
}
|
specialCachedValue.serialize(data, 10+offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
LittleEndian.putShort(data, 18 + offset, getOptions());
|
||||||
|
|
||||||
|
//when writing the chn field (offset 20), it's supposed to be 0 but ignored on read
|
||||||
|
//Microsoft Excel Developer's Kit Page 318
|
||||||
|
LittleEndian.putInt(data, 20 + offset, 0);
|
||||||
|
int formulaTokensSize = Ptg.getEncodedSizeWithoutArrayData(field_8_parsed_expr);
|
||||||
|
LittleEndian.putUShort(data, 24 + offset, formulaTokensSize);
|
||||||
|
Ptg.serializePtgs(field_8_parsed_expr, data, 26+offset);
|
||||||
|
return 4 + dataSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getRecordSize() {
|
||||||
|
return 4 + getDataSize();
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isInValueSection() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isValue() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String toString() {
|
||||||
|
|
||||||
|
StringBuffer sb = new StringBuffer();
|
||||||
|
sb.append("[FORMULA]\n");
|
||||||
|
sb.append(" .row = ").append(HexDump.shortToHex(getRow())).append("\n");
|
||||||
|
sb.append(" .column = ").append(HexDump.shortToHex(getColumn())).append("\n");
|
||||||
|
sb.append(" .xf = ").append(HexDump.shortToHex(getXFIndex())).append("\n");
|
||||||
|
sb.append(" .value = ");
|
||||||
|
if (specialCachedValue == null) {
|
||||||
|
sb.append(field_4_value).append("\n");
|
||||||
|
} else {
|
||||||
|
sb.append(specialCachedValue.formatDebugString()).append("\n");
|
||||||
|
}
|
||||||
|
sb.append(" .options = ").append(HexDump.shortToHex(getOptions())).append("\n");
|
||||||
|
sb.append(" .alwaysCalc= ").append(alwaysCalc.isSet(getOptions())).append("\n");
|
||||||
|
sb.append(" .calcOnLoad= ").append(calcOnLoad.isSet(getOptions())).append("\n");
|
||||||
|
sb.append(" .shared = ").append(sharedFormula.isSet(getOptions())).append("\n");
|
||||||
|
sb.append(" .zero = ").append(HexDump.intToHex(field_6_zero)).append("\n");
|
||||||
|
|
||||||
|
for (int k = 0; k < field_8_parsed_expr.length; k++ ) {
|
||||||
|
sb.append(" Ptg[").append(k).append("]=");
|
||||||
|
Ptg ptg = field_8_parsed_expr[k];
|
||||||
|
sb.append(ptg.toString()).append(ptg.getRVAType()).append("\n");
|
||||||
|
}
|
||||||
|
sb.append("[/FORMULA]\n");
|
||||||
|
return sb.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Object clone() {
|
||||||
|
FormulaRecord rec = new FormulaRecord();
|
||||||
|
rec.field_1_row = field_1_row;
|
||||||
|
rec.field_2_column = field_2_column;
|
||||||
|
rec.field_3_xf = field_3_xf;
|
||||||
|
rec.field_4_value = field_4_value;
|
||||||
|
rec.field_5_options = field_5_options;
|
||||||
|
rec.field_6_zero = field_6_zero;
|
||||||
|
int nTokens = field_8_parsed_expr.length;
|
||||||
|
Ptg[] ptgs = new Ptg[nTokens];
|
||||||
|
for (int i = 0; i < nTokens; i++) {
|
||||||
|
ptgs[i] = field_8_parsed_expr[i].copy();
|
||||||
|
}
|
||||||
|
rec.field_8_parsed_expr = ptgs;
|
||||||
|
rec.specialCachedValue = specialCachedValue;
|
||||||
|
return rec;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -209,30 +209,18 @@ public class RecordInputStream extends InputStream {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
byte[] NAN_data = null;
|
|
||||||
public double readDouble() {
|
public double readDouble() {
|
||||||
checkRecordPosition();
|
checkRecordPosition();
|
||||||
//Reset NAN data
|
long valueLongBits = LittleEndian.getLong(data, recordOffset);
|
||||||
NAN_data = null;
|
double result = Double.longBitsToDouble(valueLongBits);
|
||||||
double result = LittleEndian.getDouble(data, recordOffset);
|
|
||||||
//Excel represents NAN in several ways, at this point in time we do not often
|
|
||||||
//know the sequence of bytes, so as a hack we store the NAN byte sequence
|
|
||||||
//so that it is not corrupted.
|
|
||||||
if (Double.isNaN(result)) {
|
if (Double.isNaN(result)) {
|
||||||
NAN_data = new byte[8];
|
throw new RuntimeException("Did not expect to read NaN");
|
||||||
System.arraycopy(data, recordOffset, NAN_data, 0, 8);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
recordOffset += LittleEndian.DOUBLE_SIZE;
|
recordOffset += LittleEndian.DOUBLE_SIZE;
|
||||||
pos += LittleEndian.DOUBLE_SIZE;
|
pos += LittleEndian.DOUBLE_SIZE;
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
public byte[] getNANData() {
|
|
||||||
if (NAN_data == null)
|
|
||||||
throw new RecordFormatException("Do NOT call getNANData without calling readDouble that returns NaN");
|
|
||||||
return NAN_data;
|
|
||||||
}
|
|
||||||
|
|
||||||
public short[] readShortArray() {
|
public short[] readShortArray() {
|
||||||
checkRecordPosition();
|
checkRecordPosition();
|
||||||
|
@ -276,9 +264,6 @@ public class RecordInputStream extends InputStream {
|
||||||
}
|
}
|
||||||
|
|
||||||
public String readCompressedUnicode(int length) {
|
public String readCompressedUnicode(int length) {
|
||||||
if(length == 0) {
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
if ((length < 0) || ((remaining() < length) && !isContinueNext())) {
|
if ((length < 0) || ((remaining() < length) && !isContinueNext())) {
|
||||||
throw new IllegalArgumentException("Illegal length " + length);
|
throw new IllegalArgumentException("Illegal length " + length);
|
||||||
}
|
}
|
||||||
|
@ -291,9 +276,7 @@ public class RecordInputStream extends InputStream {
|
||||||
if(compressByte != 0) throw new IllegalArgumentException("compressByte in continue records must be 0 while reading compressed unicode");
|
if(compressByte != 0) throw new IllegalArgumentException("compressByte in continue records must be 0 while reading compressed unicode");
|
||||||
}
|
}
|
||||||
byte b = readByte();
|
byte b = readByte();
|
||||||
//Typecast direct to char from byte with high bit set causes all ones
|
char ch = (char)(0x00FF & b); // avoid sex
|
||||||
//in the high byte of the char (which is of course incorrect)
|
|
||||||
char ch = (char)( (short)0xff & (short)b );
|
|
||||||
buf.append(ch);
|
buf.append(ch);
|
||||||
}
|
}
|
||||||
return buf.toString();
|
return buf.toString();
|
||||||
|
|
|
@ -20,6 +20,7 @@ package org.apache.poi.hssf.record.aggregates;
|
||||||
import org.apache.poi.hssf.record.CellValueRecordInterface;
|
import org.apache.poi.hssf.record.CellValueRecordInterface;
|
||||||
import org.apache.poi.hssf.record.FormulaRecord;
|
import org.apache.poi.hssf.record.FormulaRecord;
|
||||||
import org.apache.poi.hssf.record.Record;
|
import org.apache.poi.hssf.record.Record;
|
||||||
|
import org.apache.poi.hssf.record.RecordFormatException;
|
||||||
import org.apache.poi.hssf.record.StringRecord;
|
import org.apache.poi.hssf.record.StringRecord;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -34,9 +35,9 @@ public final class FormulaRecordAggregate extends RecordAggregate implements Cel
|
||||||
private SharedValueManager _sharedValueManager;
|
private SharedValueManager _sharedValueManager;
|
||||||
/** caches the calculated result of the formula */
|
/** caches the calculated result of the formula */
|
||||||
private StringRecord _stringRecord;
|
private StringRecord _stringRecord;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param stringRec may be <code>null</code> if this formula does not have a cached text
|
* @param stringRec may be <code>null</code> if this formula does not have a cached text
|
||||||
* value.
|
* value.
|
||||||
* @param svm the {@link SharedValueManager} for the current sheet
|
* @param svm the {@link SharedValueManager} for the current sheet
|
||||||
*/
|
*/
|
||||||
|
@ -44,6 +45,14 @@ public final class FormulaRecordAggregate extends RecordAggregate implements Cel
|
||||||
if (svm == null) {
|
if (svm == null) {
|
||||||
throw new IllegalArgumentException("sfm must not be null");
|
throw new IllegalArgumentException("sfm must not be null");
|
||||||
}
|
}
|
||||||
|
boolean hasStringRec = stringRec != null;
|
||||||
|
boolean hasCachedStringFlag = formulaRec.hasCachedResultString();
|
||||||
|
if (hasStringRec != hasCachedStringFlag) {
|
||||||
|
throw new RecordFormatException("String record was "
|
||||||
|
+ (hasStringRec ? "": "not ") + " supplied but formula record flag is "
|
||||||
|
+ (hasCachedStringFlag ? "" : "not ") + " set");
|
||||||
|
}
|
||||||
|
|
||||||
if (formulaRec.isSharedFormula()) {
|
if (formulaRec.isSharedFormula()) {
|
||||||
svm.convertSharedFormulaRecord(formulaRec);
|
svm.convertSharedFormulaRecord(formulaRec);
|
||||||
}
|
}
|
||||||
|
@ -52,18 +61,18 @@ public final class FormulaRecordAggregate extends RecordAggregate implements Cel
|
||||||
_stringRecord = stringRec;
|
_stringRecord = stringRec;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setStringRecord(StringRecord stringRecord) {
|
|
||||||
_stringRecord = stringRecord;
|
|
||||||
}
|
|
||||||
|
|
||||||
public FormulaRecord getFormulaRecord() {
|
public FormulaRecord getFormulaRecord() {
|
||||||
return _formulaRecord;
|
return _formulaRecord;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* debug only
|
||||||
|
* TODO - encapsulate
|
||||||
|
*/
|
||||||
public StringRecord getStringRecord() {
|
public StringRecord getStringRecord() {
|
||||||
return _stringRecord;
|
return _stringRecord;
|
||||||
}
|
}
|
||||||
|
|
||||||
public short getXFIndex() {
|
public short getXFIndex() {
|
||||||
return _formulaRecord.getXFIndex();
|
return _formulaRecord.getXFIndex();
|
||||||
}
|
}
|
||||||
|
@ -91,7 +100,7 @@ public final class FormulaRecordAggregate extends RecordAggregate implements Cel
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return _formulaRecord.toString();
|
return _formulaRecord.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void visitContainedRecords(RecordVisitor rv) {
|
public void visitContainedRecords(RecordVisitor rv) {
|
||||||
rv.visitRecord(_formulaRecord);
|
rv.visitRecord(_formulaRecord);
|
||||||
Record sharedFormulaRecord = _sharedValueManager.getRecordForFirstCell(_formulaRecord);
|
Record sharedFormulaRecord = _sharedValueManager.getRecordForFirstCell(_formulaRecord);
|
||||||
|
@ -102,11 +111,33 @@ public final class FormulaRecordAggregate extends RecordAggregate implements Cel
|
||||||
rv.visitRecord(_stringRecord);
|
rv.visitRecord(_stringRecord);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getStringValue() {
|
public String getStringValue() {
|
||||||
if(_stringRecord==null) {
|
if(_stringRecord==null) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
return _stringRecord.getString();
|
return _stringRecord.getString();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setCachedStringResult(String value) {
|
||||||
|
|
||||||
|
// Save the string into a String Record, creating one if required
|
||||||
|
if(_stringRecord == null) {
|
||||||
|
_stringRecord = new StringRecord();
|
||||||
|
}
|
||||||
|
_stringRecord.setString(value);
|
||||||
|
if (value.length() < 1) {
|
||||||
|
_formulaRecord.setCachedResultTypeEmptyString();
|
||||||
|
} else {
|
||||||
|
_formulaRecord.setCachedResultTypeString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public void setCachedBooleanResult(boolean value) {
|
||||||
|
_stringRecord = null;
|
||||||
|
_formulaRecord.setCachedResultBoolean(value);
|
||||||
|
}
|
||||||
|
public void setCachedErrorResult(int errorCode) {
|
||||||
|
_stringRecord = null;
|
||||||
|
_formulaRecord.setCachedResultErrorCode(errorCode);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,6 +23,7 @@ import java.util.Calendar;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
import org.apache.poi.hssf.model.FormulaParser;
|
import org.apache.poi.hssf.model.FormulaParser;
|
||||||
import org.apache.poi.hssf.model.Sheet;
|
import org.apache.poi.hssf.model.Sheet;
|
||||||
|
@ -55,8 +56,8 @@ import org.apache.poi.hssf.record.formula.eval.ErrorEval;
|
||||||
* Cells can be numeric, formula-based or string-based (text). The cell type
|
* Cells can be numeric, formula-based or string-based (text). The cell type
|
||||||
* specifies this. String cells cannot conatin numbers and numeric cells cannot
|
* specifies this. String cells cannot conatin numbers and numeric cells cannot
|
||||||
* contain strings (at least according to our model). Client apps should do the
|
* contain strings (at least according to our model). Client apps should do the
|
||||||
* conversions themselves. Formula cells have the formula string, as well as
|
* conversions themselves. Formula cells have the formula string, as well as
|
||||||
* the formula result, which can be numeric or string.
|
* the formula result, which can be numeric or string.
|
||||||
* <p>
|
* <p>
|
||||||
* Cells should have their number (0 based) before being added to a row. Only
|
* Cells should have their number (0 based) before being added to a row. Only
|
||||||
* cells that have values should be added.
|
* cells that have values should be added.
|
||||||
|
@ -82,14 +83,15 @@ public final class HSSFCell {
|
||||||
public final static int CELL_TYPE_BOOLEAN = 4;
|
public final static int CELL_TYPE_BOOLEAN = 4;
|
||||||
/** Error Cell type (5) @see #setCellType(int) @see #getCellType() */
|
/** Error Cell type (5) @see #setCellType(int) @see #getCellType() */
|
||||||
public final static int CELL_TYPE_ERROR = 5;
|
public final static int CELL_TYPE_ERROR = 5;
|
||||||
|
|
||||||
public final static short ENCODING_UNCHANGED = -1;
|
public final static short ENCODING_UNCHANGED = -1;
|
||||||
public final static short ENCODING_COMPRESSED_UNICODE = 0;
|
public final static short ENCODING_COMPRESSED_UNICODE = 0;
|
||||||
public final static short ENCODING_UTF_16 = 1;
|
public final static short ENCODING_UTF_16 = 1;
|
||||||
|
|
||||||
|
private final HSSFWorkbook book;
|
||||||
|
private final Sheet sheet;
|
||||||
private int cellType;
|
private int cellType;
|
||||||
private HSSFRichTextString stringValue;
|
private HSSFRichTextString stringValue;
|
||||||
private HSSFWorkbook book;
|
|
||||||
private Sheet sheet;
|
|
||||||
private CellValueRecordInterface record;
|
private CellValueRecordInterface record;
|
||||||
private HSSFComment comment;
|
private HSSFComment comment;
|
||||||
|
|
||||||
|
@ -122,6 +124,9 @@ public final class HSSFCell {
|
||||||
short xfindex = sheet.getXFIndexForColAt(col);
|
short xfindex = sheet.getXFIndexForColAt(col);
|
||||||
setCellType(CELL_TYPE_BLANK, false, row, col,xfindex);
|
setCellType(CELL_TYPE_BLANK, false, row, col,xfindex);
|
||||||
}
|
}
|
||||||
|
/* package */ Sheet getSheet() {
|
||||||
|
return sheet;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates new Cell - Should only be called by HSSFRow. This creates a cell
|
* Creates new Cell - Should only be called by HSSFRow. This creates a cell
|
||||||
|
@ -144,7 +149,7 @@ public final class HSSFCell {
|
||||||
stringValue = null;
|
stringValue = null;
|
||||||
this.book = book;
|
this.book = book;
|
||||||
this.sheet = sheet;
|
this.sheet = sheet;
|
||||||
|
|
||||||
short xfindex = sheet.getXFIndexForColAt(col);
|
short xfindex = sheet.getXFIndexForColAt(col);
|
||||||
setCellType(type,false,row,col,xfindex);
|
setCellType(type,false,row,col,xfindex);
|
||||||
}
|
}
|
||||||
|
@ -186,10 +191,10 @@ public final class HSSFCell {
|
||||||
* used internally -- given a cell value record, figure out its type
|
* used internally -- given a cell value record, figure out its type
|
||||||
*/
|
*/
|
||||||
private static int determineType(CellValueRecordInterface cval) {
|
private static int determineType(CellValueRecordInterface cval) {
|
||||||
if (cval instanceof FormulaRecordAggregate) {
|
if (cval instanceof FormulaRecordAggregate) {
|
||||||
return HSSFCell.CELL_TYPE_FORMULA;
|
return HSSFCell.CELL_TYPE_FORMULA;
|
||||||
}
|
}
|
||||||
// all others are plain BIFF records
|
// all others are plain BIFF records
|
||||||
Record record = ( Record ) cval;
|
Record record = ( Record ) cval;
|
||||||
switch (record.getSid()) {
|
switch (record.getSid()) {
|
||||||
|
|
||||||
|
@ -205,13 +210,13 @@ public final class HSSFCell {
|
||||||
}
|
}
|
||||||
throw new RuntimeException("Bad cell value rec (" + cval.getClass().getName() + ")");
|
throw new RuntimeException("Bad cell value rec (" + cval.getClass().getName() + ")");
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the Workbook that this Cell is bound to
|
* Returns the Workbook that this Cell is bound to
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
protected Workbook getBoundWorkbook() {
|
protected Workbook getBoundWorkbook() {
|
||||||
return book.getWorkbook();
|
return book.getWorkbook();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -229,7 +234,7 @@ public final class HSSFCell {
|
||||||
{
|
{
|
||||||
record.setColumn(num);
|
record.setColumn(num);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Updates the cell record's idea of what
|
* Updates the cell record's idea of what
|
||||||
* column it belongs in (0 based)
|
* column it belongs in (0 based)
|
||||||
|
@ -237,7 +242,7 @@ public final class HSSFCell {
|
||||||
*/
|
*/
|
||||||
protected void updateCellNum(short num)
|
protected void updateCellNum(short num)
|
||||||
{
|
{
|
||||||
record.setColumn(num);
|
record.setColumn(num);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -417,14 +422,14 @@ public final class HSSFCell {
|
||||||
errRec.setColumn(col);
|
errRec.setColumn(col);
|
||||||
if (setValue)
|
if (setValue)
|
||||||
{
|
{
|
||||||
errRec.setValue(getErrorCellValue());
|
errRec.setValue((byte)HSSFErrorConstants.ERROR_VALUE);
|
||||||
}
|
}
|
||||||
errRec.setXFIndex(styleIndex);
|
errRec.setXFIndex(styleIndex);
|
||||||
errRec.setRow(row);
|
errRec.setRow(row);
|
||||||
record = errRec;
|
record = errRec;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (cellType != this.cellType &&
|
if (cellType != this.cellType &&
|
||||||
this.cellType!=-1 ) // Special Value to indicate an uninitialized Cell
|
this.cellType!=-1 ) // Special Value to indicate an uninitialized Cell
|
||||||
{
|
{
|
||||||
sheet.replaceValueRecord(record);
|
sheet.replaceValueRecord(record);
|
||||||
|
@ -453,21 +458,20 @@ public final class HSSFCell {
|
||||||
* precalculated value, for numerics we'll set its value. For other types we
|
* precalculated value, for numerics we'll set its value. For other types we
|
||||||
* will change the cell to a numeric cell and set its value.
|
* will change the cell to a numeric cell and set its value.
|
||||||
*/
|
*/
|
||||||
public void setCellValue(double value)
|
public void setCellValue(double value) {
|
||||||
{
|
|
||||||
int row=record.getRow();
|
int row=record.getRow();
|
||||||
short col=record.getColumn();
|
short col=record.getColumn();
|
||||||
short styleIndex=record.getXFIndex();
|
short styleIndex=record.getXFIndex();
|
||||||
if ((cellType != CELL_TYPE_NUMERIC) && (cellType != CELL_TYPE_FORMULA))
|
|
||||||
{
|
switch (cellType) {
|
||||||
setCellType(CELL_TYPE_NUMERIC, false, row, col, styleIndex);
|
default:
|
||||||
}
|
setCellType(CELL_TYPE_NUMERIC, false, row, col, styleIndex);
|
||||||
|
case CELL_TYPE_ERROR:
|
||||||
// Save into the appropriate record
|
(( NumberRecord ) record).setValue(value);
|
||||||
if(record instanceof FormulaRecordAggregate) {
|
break;
|
||||||
(( FormulaRecordAggregate ) record).getFormulaRecord().setValue(value);
|
case CELL_TYPE_FORMULA:
|
||||||
} else {
|
((FormulaRecordAggregate)record).getFormulaRecord().setValue(value);
|
||||||
(( NumberRecord ) record).setValue(value);
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -487,7 +491,7 @@ public final class HSSFCell {
|
||||||
/**
|
/**
|
||||||
* set a date value for the cell. Excel treats dates as numeric so you will need to format the cell as
|
* set a date value for the cell. Excel treats dates as numeric so you will need to format the cell as
|
||||||
* a date.
|
* a date.
|
||||||
*
|
*
|
||||||
* This will set the cell value based on the Calendar's timezone. As Excel
|
* This will set the cell value based on the Calendar's timezone. As Excel
|
||||||
* does not support timezones this means that both 20:00+03:00 and
|
* does not support timezones this means that both 20:00+03:00 and
|
||||||
* 20:00-03:00 will be reported as the same value (20:00) even that there
|
* 20:00-03:00 will be reported as the same value (20:00) even that there
|
||||||
|
@ -539,31 +543,20 @@ public final class HSSFCell {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (cellType == CELL_TYPE_FORMULA) {
|
if (cellType == CELL_TYPE_FORMULA) {
|
||||||
// Set the 'pre-evaluated result' for the formula
|
// Set the 'pre-evaluated result' for the formula
|
||||||
// note - formulas do not preserve text formatting.
|
// note - formulas do not preserve text formatting.
|
||||||
FormulaRecordAggregate fr = (FormulaRecordAggregate) record;
|
FormulaRecordAggregate fr = (FormulaRecordAggregate) record;
|
||||||
|
fr.setCachedStringResult(value.getString());
|
||||||
// Save the string into a String Record, creating
|
|
||||||
// one if required
|
|
||||||
StringRecord sr = fr.getStringRecord();
|
|
||||||
if(sr == null) {
|
|
||||||
// Wasn't a string before, need a new one
|
|
||||||
sr = new StringRecord();
|
|
||||||
fr.setStringRecord(sr);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Save, loosing the formatting
|
|
||||||
sr.setString(value.getString());
|
|
||||||
// Update our local cache to the un-formatted version
|
// Update our local cache to the un-formatted version
|
||||||
stringValue = new HSSFRichTextString(sr.getString());
|
stringValue = new HSSFRichTextString(value.getString());
|
||||||
|
|
||||||
// All done
|
// All done
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// If we get here, we're not dealing with a formula,
|
// If we get here, we're not dealing with a formula,
|
||||||
// so handle things as a normal rich text cell
|
// so handle things as a normal rich text cell
|
||||||
|
|
||||||
if (cellType != CELL_TYPE_STRING) {
|
if (cellType != CELL_TYPE_STRING) {
|
||||||
setCellType(CELL_TYPE_STRING, false, row, col, styleIndex);
|
setCellType(CELL_TYPE_STRING, false, row, col, styleIndex);
|
||||||
}
|
}
|
||||||
|
@ -591,95 +584,95 @@ public final class HSSFCell {
|
||||||
FormulaRecord frec = rec.getFormulaRecord();
|
FormulaRecord frec = rec.getFormulaRecord();
|
||||||
frec.setOptions((short) 2);
|
frec.setOptions((short) 2);
|
||||||
frec.setValue(0);
|
frec.setValue(0);
|
||||||
|
|
||||||
//only set to default if there is no extended format index already set
|
//only set to default if there is no extended format index already set
|
||||||
if (rec.getXFIndex() == (short)0) {
|
if (rec.getXFIndex() == (short)0) {
|
||||||
rec.setXFIndex((short) 0x0f);
|
rec.setXFIndex((short) 0x0f);
|
||||||
}
|
}
|
||||||
Ptg[] ptgs = FormulaParser.parse(formula, book);
|
Ptg[] ptgs = FormulaParser.parse(formula, book);
|
||||||
frec.setParsedExpression(ptgs);
|
frec.setParsedExpression(ptgs);
|
||||||
}
|
}
|
||||||
|
/* package */ void setFormulaOnly(Ptg[] ptgs) {
|
||||||
|
if (ptgs == null) {
|
||||||
|
throw new IllegalArgumentException("ptgs must not be null");
|
||||||
|
}
|
||||||
|
((FormulaRecordAggregate)record).getFormulaRecord().setParsedExpression(ptgs);
|
||||||
|
}
|
||||||
|
|
||||||
public String getCellFormula() {
|
public String getCellFormula() {
|
||||||
return FormulaParser.toFormulaString(book, ((FormulaRecordAggregate)record).getFormulaRecord().getParsedExpression());
|
return FormulaParser.toFormulaString(book, ((FormulaRecordAggregate)record).getFormulaRecord().getParsedExpression());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Used to help format error messages
|
||||||
|
*/
|
||||||
|
private static String getCellTypeName(int cellTypeCode) {
|
||||||
|
switch (cellTypeCode) {
|
||||||
|
case CELL_TYPE_BLANK: return "blank";
|
||||||
|
case CELL_TYPE_STRING: return "text";
|
||||||
|
case CELL_TYPE_BOOLEAN: return "boolean";
|
||||||
|
case CELL_TYPE_ERROR: return "error";
|
||||||
|
case CELL_TYPE_NUMERIC: return "numeric";
|
||||||
|
case CELL_TYPE_FORMULA: return "formula";
|
||||||
|
}
|
||||||
|
return "#unknown cell type (" + cellTypeCode + ")#";
|
||||||
|
}
|
||||||
|
|
||||||
|
private static RuntimeException typeMismatch(int expectedTypeCode, int actualTypeCode, boolean isFormulaCell) {
|
||||||
|
String msg = "Cannot get a "
|
||||||
|
+ getCellTypeName(expectedTypeCode) + " value from a "
|
||||||
|
+ getCellTypeName(actualTypeCode) + " " + (isFormulaCell ? "formula " : "") + "cell";
|
||||||
|
return new IllegalStateException(msg);
|
||||||
|
}
|
||||||
|
private static void checkFormulaCachedValueType(int expectedTypeCode, FormulaRecord fr) {
|
||||||
|
int cachedValueType = fr.getCachedResultType();
|
||||||
|
if (cachedValueType != expectedTypeCode) {
|
||||||
|
throw typeMismatch(expectedTypeCode, cachedValueType, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the value of the cell as a number.
|
* Get the value of the cell as a number.
|
||||||
* For strings we throw an exception.
|
* For strings we throw an exception.
|
||||||
* For blank cells we return a 0.
|
* For blank cells we return a 0.
|
||||||
* See {@link HSSFDataFormatter} for turning this
|
* See {@link HSSFDataFormatter} for turning this
|
||||||
* number into a string similar to that which
|
* number into a string similar to that which
|
||||||
* Excel would render this number as.
|
* Excel would render this number as.
|
||||||
*/
|
*/
|
||||||
public double getNumericCellValue()
|
public double getNumericCellValue() {
|
||||||
{
|
|
||||||
if (cellType == CELL_TYPE_BLANK)
|
switch(cellType) {
|
||||||
{
|
case CELL_TYPE_BLANK:
|
||||||
return 0;
|
return 0.0;
|
||||||
|
case CELL_TYPE_NUMERIC:
|
||||||
|
return ((NumberRecord)record).getValue();
|
||||||
|
default:
|
||||||
|
throw typeMismatch(CELL_TYPE_NUMERIC, cellType, false);
|
||||||
|
case CELL_TYPE_FORMULA:
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
if (cellType == CELL_TYPE_STRING)
|
FormulaRecord fr = ((FormulaRecordAggregate)record).getFormulaRecord();
|
||||||
{
|
checkFormulaCachedValueType(CELL_TYPE_NUMERIC, fr);
|
||||||
throw new NumberFormatException(
|
return fr.getValue();
|
||||||
"You cannot get a numeric value from a String based cell");
|
|
||||||
}
|
|
||||||
if (cellType == CELL_TYPE_BOOLEAN)
|
|
||||||
{
|
|
||||||
throw new NumberFormatException(
|
|
||||||
"You cannot get a numeric value from a boolean cell");
|
|
||||||
}
|
|
||||||
if (cellType == CELL_TYPE_ERROR)
|
|
||||||
{
|
|
||||||
throw new NumberFormatException(
|
|
||||||
"You cannot get a numeric value from an error cell");
|
|
||||||
}
|
|
||||||
if(cellType == CELL_TYPE_NUMERIC)
|
|
||||||
{
|
|
||||||
return ((NumberRecord)record).getValue();
|
|
||||||
}
|
|
||||||
if(cellType == CELL_TYPE_FORMULA)
|
|
||||||
{
|
|
||||||
return ((FormulaRecordAggregate)record).getFormulaRecord().getValue();
|
|
||||||
}
|
|
||||||
throw new NumberFormatException("Unknown Record Type in Cell:"+cellType);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the value of the cell as a date.
|
* Get the value of the cell as a date.
|
||||||
* For strings we throw an exception.
|
* For strings we throw an exception.
|
||||||
* For blank cells we return a null.
|
* For blank cells we return a null.
|
||||||
* See {@link HSSFDataFormatter} for formatting
|
* See {@link HSSFDataFormatter} for formatting
|
||||||
* this date into a string similar to how excel does.
|
* this date into a string similar to how excel does.
|
||||||
*/
|
*/
|
||||||
public Date getDateCellValue()
|
public Date getDateCellValue() {
|
||||||
{
|
|
||||||
if (cellType == CELL_TYPE_BLANK)
|
if (cellType == CELL_TYPE_BLANK) {
|
||||||
{
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
if (cellType == CELL_TYPE_STRING)
|
double value = getNumericCellValue();
|
||||||
{
|
|
||||||
throw new NumberFormatException(
|
|
||||||
"You cannot get a date value from a String based cell");
|
|
||||||
}
|
|
||||||
if (cellType == CELL_TYPE_BOOLEAN)
|
|
||||||
{
|
|
||||||
throw new NumberFormatException(
|
|
||||||
"You cannot get a date value from a boolean cell");
|
|
||||||
}
|
|
||||||
if (cellType == CELL_TYPE_ERROR)
|
|
||||||
{
|
|
||||||
throw new NumberFormatException(
|
|
||||||
"You cannot get a date value from an error cell");
|
|
||||||
}
|
|
||||||
double value=this.getNumericCellValue();
|
|
||||||
if (book.getWorkbook().isUsing1904DateWindowing()) {
|
if (book.getWorkbook().isUsing1904DateWindowing()) {
|
||||||
return HSSFDateUtil.getJavaDate(value,true);
|
return HSSFDateUtil.getJavaDate(value, true);
|
||||||
}
|
|
||||||
else {
|
|
||||||
return HSSFDateUtil.getJavaDate(value,false);
|
|
||||||
}
|
}
|
||||||
|
return HSSFDateUtil.getJavaDate(value, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -700,33 +693,22 @@ public final class HSSFCell {
|
||||||
* For blank cells we return an empty string.
|
* For blank cells we return an empty string.
|
||||||
* For formulaCells that are not string Formulas, we return empty String
|
* For formulaCells that are not string Formulas, we return empty String
|
||||||
*/
|
*/
|
||||||
|
public HSSFRichTextString getRichStringCellValue() {
|
||||||
|
|
||||||
public HSSFRichTextString getRichStringCellValue()
|
switch(cellType) {
|
||||||
{
|
case CELL_TYPE_BLANK:
|
||||||
if (cellType == CELL_TYPE_BLANK)
|
return new HSSFRichTextString("");
|
||||||
{
|
case CELL_TYPE_STRING:
|
||||||
return new HSSFRichTextString("");
|
return stringValue;
|
||||||
|
default:
|
||||||
|
throw typeMismatch(CELL_TYPE_STRING, cellType, false);
|
||||||
|
case CELL_TYPE_FORMULA:
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
if (cellType == CELL_TYPE_NUMERIC)
|
FormulaRecordAggregate fra = ((FormulaRecordAggregate)record);
|
||||||
{
|
checkFormulaCachedValueType(CELL_TYPE_STRING, fra.getFormulaRecord());
|
||||||
throw new NumberFormatException(
|
String strVal = fra.getStringValue();
|
||||||
"You cannot get a string value from a numeric cell");
|
return new HSSFRichTextString(strVal == null ? "" : strVal);
|
||||||
}
|
|
||||||
if (cellType == CELL_TYPE_BOOLEAN)
|
|
||||||
{
|
|
||||||
throw new NumberFormatException(
|
|
||||||
"You cannot get a string value from a boolean cell");
|
|
||||||
}
|
|
||||||
if (cellType == CELL_TYPE_ERROR)
|
|
||||||
{
|
|
||||||
throw new NumberFormatException(
|
|
||||||
"You cannot get a string value from an error cell");
|
|
||||||
}
|
|
||||||
if (cellType == CELL_TYPE_FORMULA)
|
|
||||||
{
|
|
||||||
if (stringValue==null) return new HSSFRichTextString("");
|
|
||||||
}
|
|
||||||
return stringValue;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -737,47 +719,56 @@ public final class HSSFCell {
|
||||||
* will change the cell to a boolean cell and set its value.
|
* will change the cell to a boolean cell and set its value.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
public void setCellValue(boolean value)
|
public void setCellValue(boolean value) {
|
||||||
{
|
|
||||||
int row=record.getRow();
|
int row=record.getRow();
|
||||||
short col=record.getColumn();
|
short col=record.getColumn();
|
||||||
short styleIndex=record.getXFIndex();
|
short styleIndex=record.getXFIndex();
|
||||||
if ((cellType != CELL_TYPE_BOOLEAN ) && ( cellType != CELL_TYPE_FORMULA))
|
|
||||||
{
|
switch (cellType) {
|
||||||
setCellType(CELL_TYPE_BOOLEAN, false, row, col, styleIndex);
|
default:
|
||||||
|
setCellType(CELL_TYPE_BOOLEAN, false, row, col, styleIndex);
|
||||||
|
case CELL_TYPE_ERROR:
|
||||||
|
(( BoolErrRecord ) record).setValue(value);
|
||||||
|
break;
|
||||||
|
case CELL_TYPE_FORMULA:
|
||||||
|
((FormulaRecordAggregate)record).getFormulaRecord().setCachedResultBoolean(value);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
(( BoolErrRecord ) record).setValue(value);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* set a error value for the cell
|
* set a error value for the cell
|
||||||
*
|
*
|
||||||
* @param value the error value to set this cell to. For formulas we'll set the
|
* @param errorCode the error value to set this cell to. For formulas we'll set the
|
||||||
* precalculated value ??? IS THIS RIGHT??? , for errors we'll set
|
* precalculated value , for errors we'll set
|
||||||
* its value. For other types we will change the cell to an error
|
* its value. For other types we will change the cell to an error
|
||||||
* cell and set its value.
|
* cell and set its value.
|
||||||
*/
|
*/
|
||||||
|
public void setCellErrorValue(byte errorCode) {
|
||||||
public void setCellErrorValue(byte value)
|
|
||||||
{
|
|
||||||
int row=record.getRow();
|
int row=record.getRow();
|
||||||
short col=record.getColumn();
|
short col=record.getColumn();
|
||||||
short styleIndex=record.getXFIndex();
|
short styleIndex=record.getXFIndex();
|
||||||
if (cellType != CELL_TYPE_ERROR) {
|
switch (cellType) {
|
||||||
setCellType(CELL_TYPE_ERROR, false, row, col, styleIndex);
|
default:
|
||||||
|
setCellType(CELL_TYPE_ERROR, false, row, col, styleIndex);
|
||||||
|
case CELL_TYPE_ERROR:
|
||||||
|
(( BoolErrRecord ) record).setValue(errorCode);
|
||||||
|
break;
|
||||||
|
case CELL_TYPE_FORMULA:
|
||||||
|
((FormulaRecordAggregate)record).getFormulaRecord().setCachedResultErrorCode(errorCode);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
(( BoolErrRecord ) record).setValue(value);
|
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* Chooses a new boolean value for the cell when its type is changing.<p/>
|
* Chooses a new boolean value for the cell when its type is changing.<p/>
|
||||||
*
|
*
|
||||||
* Usually the caller is calling setCellType() with the intention of calling
|
* Usually the caller is calling setCellType() with the intention of calling
|
||||||
* setCellValue(boolean) straight afterwards. This method only exists to give
|
* setCellValue(boolean) straight afterwards. This method only exists to give
|
||||||
* the cell a somewhat reasonable value until the setCellValue() call (if at all).
|
* the cell a somewhat reasonable value until the setCellValue() call (if at all).
|
||||||
* TODO - perhaps a method like setCellTypeAndValue(int, Object) should be introduced to avoid this
|
* TODO - perhaps a method like setCellTypeAndValue(int, Object) should be introduced to avoid this
|
||||||
*/
|
*/
|
||||||
private boolean convertCellValueToBoolean() {
|
private boolean convertCellValueToBoolean() {
|
||||||
|
|
||||||
switch (cellType) {
|
switch (cellType) {
|
||||||
case CELL_TYPE_BOOLEAN:
|
case CELL_TYPE_BOOLEAN:
|
||||||
return (( BoolErrRecord ) record).getBooleanValue();
|
return (( BoolErrRecord ) record).getBooleanValue();
|
||||||
|
@ -788,11 +779,11 @@ public final class HSSFCell {
|
||||||
|
|
||||||
// All other cases convert to false
|
// All other cases convert to false
|
||||||
// These choices are not well justified.
|
// These choices are not well justified.
|
||||||
case CELL_TYPE_FORMULA:
|
case CELL_TYPE_FORMULA:
|
||||||
// should really evaluate, but HSSFCell can't call HSSFFormulaEvaluator
|
// should really evaluate, but HSSFCell can't call HSSFFormulaEvaluator
|
||||||
case CELL_TYPE_ERROR:
|
case CELL_TYPE_ERROR:
|
||||||
case CELL_TYPE_BLANK:
|
case CELL_TYPE_BLANK:
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
throw new RuntimeException("Unexpected cell type (" + cellType + ")");
|
throw new RuntimeException("Unexpected cell type (" + cellType + ")");
|
||||||
}
|
}
|
||||||
|
@ -801,38 +792,39 @@ public final class HSSFCell {
|
||||||
* get the value of the cell as a boolean. For strings, numbers, and errors, we throw an exception.
|
* get the value of the cell as a boolean. For strings, numbers, and errors, we throw an exception.
|
||||||
* For blank cells we return a false.
|
* For blank cells we return a false.
|
||||||
*/
|
*/
|
||||||
|
public boolean getBooleanCellValue() {
|
||||||
|
|
||||||
public boolean getBooleanCellValue()
|
switch(cellType) {
|
||||||
{
|
case CELL_TYPE_BLANK:
|
||||||
if (cellType == CELL_TYPE_BOOLEAN)
|
return false;
|
||||||
{
|
case CELL_TYPE_BOOLEAN:
|
||||||
return (( BoolErrRecord ) record).getBooleanValue();
|
return (( BoolErrRecord ) record).getBooleanValue();
|
||||||
|
default:
|
||||||
|
throw typeMismatch(CELL_TYPE_BOOLEAN, cellType, false);
|
||||||
|
case CELL_TYPE_FORMULA:
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
if (cellType == CELL_TYPE_BLANK)
|
FormulaRecord fr = ((FormulaRecordAggregate)record).getFormulaRecord();
|
||||||
{
|
checkFormulaCachedValueType(CELL_TYPE_BOOLEAN, fr);
|
||||||
return false;
|
return fr.getCachedBooleanValue();
|
||||||
}
|
|
||||||
throw new NumberFormatException(
|
|
||||||
"You cannot get a boolean value from a non-boolean cell");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* get the value of the cell as an error code. For strings, numbers, and booleans, we throw an exception.
|
* get the value of the cell as an error code. For strings, numbers, and booleans, we throw an exception.
|
||||||
* For blank cells we return a 0.
|
* For blank cells we return a 0.
|
||||||
*/
|
*/
|
||||||
|
public byte getErrorCellValue() {
|
||||||
public byte getErrorCellValue()
|
switch(cellType) {
|
||||||
{
|
case CELL_TYPE_ERROR:
|
||||||
if (cellType == CELL_TYPE_ERROR)
|
return (( BoolErrRecord ) record).getErrorValue();
|
||||||
{
|
default:
|
||||||
return (( BoolErrRecord ) record).getErrorValue();
|
throw typeMismatch(CELL_TYPE_ERROR, cellType, false);
|
||||||
|
case CELL_TYPE_FORMULA:
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
if (cellType == CELL_TYPE_BLANK)
|
FormulaRecord fr = ((FormulaRecordAggregate)record).getFormulaRecord();
|
||||||
{
|
checkFormulaCachedValueType(CELL_TYPE_ERROR, fr);
|
||||||
return ( byte ) 0;
|
return (byte) fr.getCachedErrorValue();
|
||||||
}
|
|
||||||
throw new NumberFormatException(
|
|
||||||
"You cannot get an error value from a non-error cell");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -888,7 +880,7 @@ public final class HSSFCell {
|
||||||
throw new RuntimeException("You cannot reference columns with an index of less then 0.");
|
throw new RuntimeException("You cannot reference columns with an index of less then 0.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets this cell as the active cell for the worksheet
|
* Sets this cell as the active cell for the worksheet
|
||||||
*/
|
*/
|
||||||
|
@ -899,42 +891,42 @@ public final class HSSFCell {
|
||||||
this.sheet.setActiveCellRow(row);
|
this.sheet.setActiveCellRow(row);
|
||||||
this.sheet.setActiveCellCol(col);
|
this.sheet.setActiveCellCol(col);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns a string representation of the cell
|
* Returns a string representation of the cell
|
||||||
*
|
*
|
||||||
* This method returns a simple representation,
|
* This method returns a simple representation,
|
||||||
* anthing more complex should be in user code, with
|
* anthing more complex should be in user code, with
|
||||||
* knowledge of the semantics of the sheet being processed.
|
* knowledge of the semantics of the sheet being processed.
|
||||||
*
|
*
|
||||||
* Formula cells return the formula string,
|
* Formula cells return the formula string,
|
||||||
* rather than the formula result.
|
* rather than the formula result.
|
||||||
* Dates are displayed in dd-MMM-yyyy format
|
* Dates are displayed in dd-MMM-yyyy format
|
||||||
* Errors are displayed as #ERR<errIdx>
|
* Errors are displayed as #ERR<errIdx>
|
||||||
*/
|
*/
|
||||||
public String toString() {
|
public String toString() {
|
||||||
switch (getCellType()) {
|
switch (getCellType()) {
|
||||||
case CELL_TYPE_BLANK:
|
case CELL_TYPE_BLANK:
|
||||||
return "";
|
return "";
|
||||||
case CELL_TYPE_BOOLEAN:
|
case CELL_TYPE_BOOLEAN:
|
||||||
return getBooleanCellValue()?"TRUE":"FALSE";
|
return getBooleanCellValue()?"TRUE":"FALSE";
|
||||||
case CELL_TYPE_ERROR:
|
case CELL_TYPE_ERROR:
|
||||||
return ErrorEval.getText((( BoolErrRecord ) record).getErrorValue());
|
return ErrorEval.getText((( BoolErrRecord ) record).getErrorValue());
|
||||||
case CELL_TYPE_FORMULA:
|
case CELL_TYPE_FORMULA:
|
||||||
return getCellFormula();
|
return getCellFormula();
|
||||||
case CELL_TYPE_NUMERIC:
|
case CELL_TYPE_NUMERIC:
|
||||||
//TODO apply the dataformat for this cell
|
//TODO apply the dataformat for this cell
|
||||||
if (HSSFDateUtil.isCellDateFormatted(this)) {
|
if (HSSFDateUtil.isCellDateFormatted(this)) {
|
||||||
DateFormat sdf = new SimpleDateFormat("dd-MMM-yyyy");
|
DateFormat sdf = new SimpleDateFormat("dd-MMM-yyyy");
|
||||||
return sdf.format(getDateCellValue());
|
return sdf.format(getDateCellValue());
|
||||||
} else {
|
} else {
|
||||||
return getNumericCellValue() + "";
|
return getNumericCellValue() + "";
|
||||||
}
|
}
|
||||||
case CELL_TYPE_STRING:
|
case CELL_TYPE_STRING:
|
||||||
return getStringCellValue();
|
return getStringCellValue();
|
||||||
default:
|
default:
|
||||||
return "Unknown Cell Type: " + getCellType();
|
return "Unknown Cell Type: " + getCellType();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -945,11 +937,11 @@ public final class HSSFCell {
|
||||||
* @param comment comment associated with this cell
|
* @param comment comment associated with this cell
|
||||||
*/
|
*/
|
||||||
public void setCellComment(HSSFComment comment){
|
public void setCellComment(HSSFComment comment){
|
||||||
if(comment == null) {
|
if(comment == null) {
|
||||||
removeCellComment();
|
removeCellComment();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
comment.setRow((short)record.getRow());
|
comment.setRow((short)record.getRow());
|
||||||
comment.setColumn(record.getColumn());
|
comment.setColumn(record.getColumn());
|
||||||
this.comment = comment;
|
this.comment = comment;
|
||||||
|
@ -966,7 +958,7 @@ public final class HSSFCell {
|
||||||
}
|
}
|
||||||
return comment;
|
return comment;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Removes the comment for this cell, if
|
* Removes the comment for this cell, if
|
||||||
* there is one.
|
* there is one.
|
||||||
|
@ -974,40 +966,41 @@ public final class HSSFCell {
|
||||||
* all comments after performing this action!
|
* all comments after performing this action!
|
||||||
*/
|
*/
|
||||||
public void removeCellComment() {
|
public void removeCellComment() {
|
||||||
HSSFComment comment = findCellComment(sheet, record.getRow(), record.getColumn());
|
HSSFComment comment = findCellComment(sheet, record.getRow(), record.getColumn());
|
||||||
this.comment = null;
|
this.comment = null;
|
||||||
|
|
||||||
if(comment == null) {
|
if(comment == null) {
|
||||||
// Nothing to do
|
// Nothing to do
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Zap the underlying NoteRecord
|
// Zap the underlying NoteRecord
|
||||||
sheet.getRecords().remove(comment.getNoteRecord());
|
List sheetRecords = sheet.getRecords();
|
||||||
|
sheetRecords.remove(comment.getNoteRecord());
|
||||||
// If we have a TextObjectRecord, is should
|
|
||||||
// be proceeed by:
|
// If we have a TextObjectRecord, is should
|
||||||
// MSODRAWING with container
|
// be proceeed by:
|
||||||
// OBJ
|
// MSODRAWING with container
|
||||||
// MSODRAWING with EscherTextboxRecord
|
// OBJ
|
||||||
if(comment.getTextObjectRecord() != null) {
|
// MSODRAWING with EscherTextboxRecord
|
||||||
TextObjectRecord txo = comment.getTextObjectRecord();
|
if(comment.getTextObjectRecord() != null) {
|
||||||
int txoAt = sheet.getRecords().indexOf(txo);
|
TextObjectRecord txo = comment.getTextObjectRecord();
|
||||||
|
int txoAt = sheetRecords.indexOf(txo);
|
||||||
if(sheet.getRecords().get(txoAt-3) instanceof DrawingRecord &&
|
|
||||||
sheet.getRecords().get(txoAt-2) instanceof ObjRecord &&
|
if(sheetRecords.get(txoAt-3) instanceof DrawingRecord &&
|
||||||
sheet.getRecords().get(txoAt-1) instanceof DrawingRecord) {
|
sheetRecords.get(txoAt-2) instanceof ObjRecord &&
|
||||||
// Zap these, in reverse order
|
sheetRecords.get(txoAt-1) instanceof DrawingRecord) {
|
||||||
sheet.getRecords().remove(txoAt-1);
|
// Zap these, in reverse order
|
||||||
sheet.getRecords().remove(txoAt-2);
|
sheetRecords.remove(txoAt-1);
|
||||||
sheet.getRecords().remove(txoAt-3);
|
sheetRecords.remove(txoAt-2);
|
||||||
} else {
|
sheetRecords.remove(txoAt-3);
|
||||||
throw new IllegalStateException("Found the wrong records before the TextObjectRecord, can't remove comment");
|
} else {
|
||||||
}
|
throw new IllegalStateException("Found the wrong records before the TextObjectRecord, can't remove comment");
|
||||||
|
}
|
||||||
// Now remove the text record
|
|
||||||
sheet.getRecords().remove(txo);
|
// Now remove the text record
|
||||||
}
|
sheetRecords.remove(txo);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1100,4 +1093,16 @@ public final class HSSFCell {
|
||||||
int eofLoc = sheet.findFirstRecordLocBySid( EOFRecord.sid );
|
int eofLoc = sheet.findFirstRecordLocBySid( EOFRecord.sid );
|
||||||
sheet.getRecords().add( eofLoc, link.record );
|
sheet.getRecords().add( eofLoc, link.record );
|
||||||
}
|
}
|
||||||
|
/**
|
||||||
|
* Only valid for formula cells
|
||||||
|
* @return one of ({@link #CELL_TYPE_NUMERIC}, {@link #CELL_TYPE_STRING},
|
||||||
|
* {@link #CELL_TYPE_BOOLEAN}, {@link #CELL_TYPE_ERROR}) depending
|
||||||
|
* on the cached value of the formula
|
||||||
|
*/
|
||||||
|
public int getCachedFormulaResultType() {
|
||||||
|
if (this.cellType != CELL_TYPE_FORMULA) {
|
||||||
|
throw new IllegalStateException("Only formula cells have cached results");
|
||||||
|
}
|
||||||
|
return ((FormulaRecordAggregate)record).getFormulaRecord().getCachedResultType();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1295,9 +1295,7 @@ public final class HSSFSheet {
|
||||||
// If any references were changed, then
|
// If any references were changed, then
|
||||||
// re-create the formula string
|
// re-create the formula string
|
||||||
if(changed) {
|
if(changed) {
|
||||||
c.setCellFormula(
|
c.setFormulaOnly(ptgs);
|
||||||
FormulaParser.toFormulaString(workbook, ptgs)
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -660,6 +660,16 @@ public class HSSFWorkbook extends POIDocument
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* package */ int findSheetIndex(Sheet sheet) {
|
||||||
|
for(int i=0; i<_sheets.size(); i++) {
|
||||||
|
HSSFSheet hSheet = (HSSFSheet) _sheets.get(i);
|
||||||
|
if(hSheet.getSheet() == sheet) {
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
throw new IllegalArgumentException("Specified sheet not found in this workbook");
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the external sheet index of the sheet
|
* Returns the external sheet index of the sheet
|
||||||
* with the given internal index, creating one
|
* with the given internal index, creating one
|
||||||
|
|
|
@ -214,7 +214,9 @@ public final class TestSheet extends TestCase {
|
||||||
records.add(new DimensionsRecord());
|
records.add(new DimensionsRecord());
|
||||||
records.add(new RowRecord(0));
|
records.add(new RowRecord(0));
|
||||||
records.add(new RowRecord(1));
|
records.add(new RowRecord(1));
|
||||||
records.add(new FormulaRecord());
|
FormulaRecord formulaRecord = new FormulaRecord();
|
||||||
|
formulaRecord.setCachedResultTypeString();
|
||||||
|
records.add(formulaRecord);
|
||||||
records.add(new StringRecord());
|
records.add(new StringRecord());
|
||||||
records.add(new RowRecord(2));
|
records.add(new RowRecord(2));
|
||||||
records.add(createWindow2Record());
|
records.add(createWindow2Record());
|
||||||
|
|
|
@ -26,12 +26,14 @@ import org.apache.poi.hssf.record.formula.FuncVarPtg;
|
||||||
import org.apache.poi.hssf.record.formula.IntPtg;
|
import org.apache.poi.hssf.record.formula.IntPtg;
|
||||||
import org.apache.poi.hssf.record.formula.Ptg;
|
import org.apache.poi.hssf.record.formula.Ptg;
|
||||||
import org.apache.poi.hssf.record.formula.RefPtg;
|
import org.apache.poi.hssf.record.formula.RefPtg;
|
||||||
|
import org.apache.poi.hssf.usermodel.HSSFCell;
|
||||||
|
import org.apache.poi.hssf.usermodel.HSSFErrorConstants;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tests the serialization and deserialization of the FormulaRecord
|
* Tests the serialization and deserialization of the FormulaRecord
|
||||||
* class works correctly.
|
* class works correctly.
|
||||||
*
|
*
|
||||||
* @author Andrew C. Oliver
|
* @author Andrew C. Oliver
|
||||||
*/
|
*/
|
||||||
public final class TestFormulaRecord extends TestCase {
|
public final class TestFormulaRecord extends TestCase {
|
||||||
|
|
||||||
|
@ -40,52 +42,66 @@ public final class TestFormulaRecord extends TestCase {
|
||||||
record.setColumn((short)0);
|
record.setColumn((short)0);
|
||||||
record.setRow(1);
|
record.setRow(1);
|
||||||
record.setXFIndex((short)4);
|
record.setXFIndex((short)4);
|
||||||
|
|
||||||
assertEquals(record.getColumn(),0);
|
assertEquals(record.getColumn(),0);
|
||||||
assertEquals(record.getRow(), 1);
|
assertEquals(record.getRow(), 1);
|
||||||
assertEquals(record.getXFIndex(),4);
|
assertEquals(record.getXFIndex(),4);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Make sure a NAN value is preserved
|
* Make sure a NAN value is preserved
|
||||||
* This formula record is a representation of =1/0 at row 0, column 0
|
* This formula record is a representation of =1/0 at row 0, column 0
|
||||||
*/
|
*/
|
||||||
public void testCheckNanPreserve() {
|
public void testCheckNanPreserve() {
|
||||||
byte[] formulaByte = new byte[29];
|
byte[] formulaByte = {
|
||||||
|
0, 0, 0, 0,
|
||||||
|
0x0F, 0x00,
|
||||||
|
|
||||||
|
// 8 bytes cached number is a 'special value' in this case
|
||||||
|
0x02, // special cached value type 'error'
|
||||||
|
0x00,
|
||||||
|
HSSFErrorConstants.ERROR_DIV_0,
|
||||||
|
0x00,
|
||||||
|
0x00,
|
||||||
|
0x00,
|
||||||
|
(byte)0xFF,
|
||||||
|
(byte)0xFF,
|
||||||
|
|
||||||
|
0x00,
|
||||||
|
0x00,
|
||||||
|
0x00,
|
||||||
|
0x00,
|
||||||
|
|
||||||
|
(byte)0xE0, //18
|
||||||
|
(byte)0xFC,
|
||||||
|
// Ptgs
|
||||||
|
0x07, 0x00, // encoded length
|
||||||
|
0x1E, 0x01, 0x00, // IntPtg(1)
|
||||||
|
0x1E, 0x00, 0x00, // IntPtg(0)
|
||||||
|
0x06, // DividePtg
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
formulaByte[4] = (byte)0x0F;
|
|
||||||
formulaByte[6] = (byte)0x02;
|
|
||||||
formulaByte[8] = (byte)0x07;
|
|
||||||
formulaByte[12] = (byte)0xFF;
|
|
||||||
formulaByte[13] = (byte)0xFF;
|
|
||||||
formulaByte[18] = (byte)0xE0;
|
|
||||||
formulaByte[19] = (byte)0xFC;
|
|
||||||
formulaByte[20] = (byte)0x07;
|
|
||||||
formulaByte[22] = (byte)0x1E;
|
|
||||||
formulaByte[23] = (byte)0x01;
|
|
||||||
formulaByte[25] = (byte)0x1E;
|
|
||||||
formulaByte[28] = (byte)0x06;
|
|
||||||
|
|
||||||
FormulaRecord record = new FormulaRecord(new TestcaseRecordInputStream(FormulaRecord.sid, (short)29, formulaByte));
|
FormulaRecord record = new FormulaRecord(new TestcaseRecordInputStream(FormulaRecord.sid, (short)29, formulaByte));
|
||||||
assertEquals("Row", 0, record.getRow());
|
assertEquals("Row", 0, record.getRow());
|
||||||
assertEquals("Column", 0, record.getColumn());
|
assertEquals("Column", 0, record.getColumn());
|
||||||
assertTrue("Value is not NaN", Double.isNaN(record.getValue()));
|
assertEquals(HSSFCell.CELL_TYPE_ERROR, record.getCachedResultType());
|
||||||
|
|
||||||
byte[] output = record.serialize();
|
byte[] output = record.serialize();
|
||||||
assertEquals("Output size", 33, output.length); //includes sid+recordlength
|
assertEquals("Output size", 33, output.length); //includes sid+recordlength
|
||||||
|
|
||||||
for (int i = 5; i < 13;i++) {
|
for (int i = 5; i < 13;i++) {
|
||||||
assertEquals("FormulaByte NaN doesn't match", formulaByte[i], output[i+4]);
|
assertEquals("FormulaByte NaN doesn't match", formulaByte[i], output[i+4]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tests to see if the shared formula cells properly reserialize the expPtg
|
* Tests to see if the shared formula cells properly reserialize the expPtg
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
public void testExpFormula() {
|
public void testExpFormula() {
|
||||||
byte[] formulaByte = new byte[27];
|
byte[] formulaByte = new byte[27];
|
||||||
|
|
||||||
formulaByte[4] =(byte)0x0F;
|
formulaByte[4] =(byte)0x0F;
|
||||||
formulaByte[14]=(byte)0x08;
|
formulaByte[14]=(byte)0x08;
|
||||||
formulaByte[18]=(byte)0xE0;
|
formulaByte[18]=(byte)0xE0;
|
||||||
|
@ -99,13 +115,13 @@ public final class TestFormulaRecord extends TestCase {
|
||||||
assertEquals("Output size", 31, output.length); //includes sid+recordlength
|
assertEquals("Output size", 31, output.length); //includes sid+recordlength
|
||||||
assertEquals("Offset 22", 1, output[26]);
|
assertEquals("Offset 22", 1, output[26]);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testWithConcat() {
|
public void testWithConcat() {
|
||||||
// =CHOOSE(2,A2,A3,A4)
|
// =CHOOSE(2,A2,A3,A4)
|
||||||
byte[] data = {
|
byte[] data = {
|
||||||
6, 0, 68, 0,
|
6, 0, 68, 0,
|
||||||
1, 0, 1, 0, 15, 0, 0, 0, 0, 0, 0, 0, 57,
|
1, 0, 1, 0, 15, 0, 0, 0, 0, 0, 0, 0, 57,
|
||||||
64, 0, 0, 12, 0, 12, -4, 46, 0,
|
64, 0, 0, 12, 0, 12, -4, 46, 0,
|
||||||
30, 2, 0, // Int - 2
|
30, 2, 0, // Int - 2
|
||||||
25, 4, 3, 0, // Attr
|
25, 4, 3, 0, // Attr
|
||||||
8, 0, 17, 0, 26, 0, // jumpTable
|
8, 0, 17, 0, 26, 0, // jumpTable
|
||||||
|
@ -115,14 +131,14 @@ public final class TestFormulaRecord extends TestCase {
|
||||||
36, 2, 0, 0, -64, // Ref - A3
|
36, 2, 0, 0, -64, // Ref - A3
|
||||||
25, 8, 12, 0, // Attr
|
25, 8, 12, 0, // Attr
|
||||||
36, 3, 0, 0, -64, // Ref - A4
|
36, 3, 0, 0, -64, // Ref - A4
|
||||||
25, 8, 3, 0, // Attr
|
25, 8, 3, 0, // Attr
|
||||||
66, 4, 100, 0 // CHOOSE
|
66, 4, 100, 0 // CHOOSE
|
||||||
};
|
};
|
||||||
RecordInputStream inp = new RecordInputStream( new ByteArrayInputStream(data));
|
RecordInputStream inp = new RecordInputStream( new ByteArrayInputStream(data));
|
||||||
inp.nextRecord();
|
inp.nextRecord();
|
||||||
|
|
||||||
FormulaRecord fr = new FormulaRecord(inp);
|
FormulaRecord fr = new FormulaRecord(inp);
|
||||||
|
|
||||||
Ptg[] ptgs = fr.getParsedExpression();
|
Ptg[] ptgs = fr.getParsedExpression();
|
||||||
assertEquals(9, ptgs.length);
|
assertEquals(9, ptgs.length);
|
||||||
assertEquals(IntPtg.class, ptgs[0].getClass());
|
assertEquals(IntPtg.class, ptgs[0].getClass());
|
||||||
|
@ -134,7 +150,7 @@ public final class TestFormulaRecord extends TestCase {
|
||||||
assertEquals(RefPtg.class, ptgs[6].getClass());
|
assertEquals(RefPtg.class, ptgs[6].getClass());
|
||||||
assertEquals(AttrPtg.class, ptgs[7].getClass());
|
assertEquals(AttrPtg.class, ptgs[7].getClass());
|
||||||
assertEquals(FuncVarPtg.class, ptgs[8].getClass());
|
assertEquals(FuncVarPtg.class, ptgs[8].getClass());
|
||||||
|
|
||||||
FuncVarPtg choose = (FuncVarPtg)ptgs[8];
|
FuncVarPtg choose = (FuncVarPtg)ptgs[8];
|
||||||
assertEquals("CHOOSE", choose.getName());
|
assertEquals("CHOOSE", choose.getName());
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,6 +30,7 @@ public final class TestFormulaRecordAggregate extends TestCase {
|
||||||
|
|
||||||
public void testBasic() throws Exception {
|
public void testBasic() throws Exception {
|
||||||
FormulaRecord f = new FormulaRecord();
|
FormulaRecord f = new FormulaRecord();
|
||||||
|
f.setCachedResultTypeString();
|
||||||
StringRecord s = new StringRecord();
|
StringRecord s = new StringRecord();
|
||||||
s.setString("abc");
|
s.setString("abc");
|
||||||
FormulaRecordAggregate fagg = new FormulaRecordAggregate(f, s, SharedValueManager.EMPTY);
|
FormulaRecordAggregate fagg = new FormulaRecordAggregate(f, s, SharedValueManager.EMPTY);
|
||||||
|
|
|
@ -961,7 +961,7 @@ public final class TestBugs extends TestCase {
|
||||||
writeOutAndReadBack(wb);
|
writeOutAndReadBack(wb);
|
||||||
assertTrue("no errors writing sample xls", true);
|
assertTrue("no errors writing sample xls", true);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Problems with extracting check boxes from
|
* Problems with extracting check boxes from
|
||||||
* HSSFObjectData
|
* HSSFObjectData
|
||||||
|
@ -973,35 +973,35 @@ public final class TestBugs extends TestCase {
|
||||||
// Take a look at the embeded objects
|
// Take a look at the embeded objects
|
||||||
List objects = wb.getAllEmbeddedObjects();
|
List objects = wb.getAllEmbeddedObjects();
|
||||||
assertEquals(1, objects.size());
|
assertEquals(1, objects.size());
|
||||||
|
|
||||||
HSSFObjectData obj = (HSSFObjectData)objects.get(0);
|
HSSFObjectData obj = (HSSFObjectData)objects.get(0);
|
||||||
assertNotNull(obj);
|
assertNotNull(obj);
|
||||||
|
|
||||||
// Peek inside the underlying record
|
// Peek inside the underlying record
|
||||||
EmbeddedObjectRefSubRecord rec = obj.findObjectRecord();
|
EmbeddedObjectRefSubRecord rec = obj.findObjectRecord();
|
||||||
assertNotNull(rec);
|
assertNotNull(rec);
|
||||||
|
|
||||||
assertEquals(32, rec.field_1_stream_id_offset);
|
assertEquals(32, rec.field_1_stream_id_offset);
|
||||||
assertEquals(0, rec.field_6_stream_id); // WRONG!
|
assertEquals(0, rec.field_6_stream_id); // WRONG!
|
||||||
assertEquals("Forms.CheckBox.1", rec.field_5_ole_classname);
|
assertEquals("Forms.CheckBox.1", rec.field_5_ole_classname);
|
||||||
assertEquals(12, rec.remainingBytes.length);
|
assertEquals(12, rec.remainingBytes.length);
|
||||||
|
|
||||||
// Doesn't have a directory
|
// Doesn't have a directory
|
||||||
assertFalse(obj.hasDirectoryEntry());
|
assertFalse(obj.hasDirectoryEntry());
|
||||||
assertNotNull(obj.getObjectData());
|
assertNotNull(obj.getObjectData());
|
||||||
assertEquals(12, obj.getObjectData().length);
|
assertEquals(12, obj.getObjectData().length);
|
||||||
assertEquals("Forms.CheckBox.1", obj.getOLE2ClassName());
|
assertEquals("Forms.CheckBox.1", obj.getOLE2ClassName());
|
||||||
|
|
||||||
try {
|
try {
|
||||||
obj.getDirectory();
|
obj.getDirectory();
|
||||||
fail();
|
fail();
|
||||||
} catch(FileNotFoundException e) {
|
} catch(FileNotFoundException e) {
|
||||||
// expectd during successful test
|
// expectd during successful test
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
throw new RuntimeException(e);
|
throw new RuntimeException(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Test that we can delete sheets without
|
* Test that we can delete sheets without
|
||||||
* breaking the build in named ranges
|
* breaking the build in named ranges
|
||||||
|
@ -1011,73 +1011,73 @@ public final class TestBugs extends TestCase {
|
||||||
HSSFWorkbook wb = openSample("30978-alt.xls");
|
HSSFWorkbook wb = openSample("30978-alt.xls");
|
||||||
assertEquals(1, wb.getNumberOfNames());
|
assertEquals(1, wb.getNumberOfNames());
|
||||||
assertEquals(3, wb.getNumberOfSheets());
|
assertEquals(3, wb.getNumberOfSheets());
|
||||||
|
|
||||||
// Check all names fit within range, and use
|
// Check all names fit within range, and use
|
||||||
// DeletedArea3DPtg
|
// DeletedArea3DPtg
|
||||||
Workbook w = wb.getWorkbook();
|
Workbook w = wb.getWorkbook();
|
||||||
for(int i=0; i<w.getNumNames(); i++) {
|
for(int i=0; i<w.getNumNames(); i++) {
|
||||||
NameRecord r = w.getNameRecord(i);
|
NameRecord r = w.getNameRecord(i);
|
||||||
assertTrue(r.getSheetNumber() <= wb.getNumberOfSheets());
|
assertTrue(r.getSheetNumber() <= wb.getNumberOfSheets());
|
||||||
|
|
||||||
Ptg[] nd = r.getNameDefinition();
|
Ptg[] nd = r.getNameDefinition();
|
||||||
assertEquals(1, nd.length);
|
assertEquals(1, nd.length);
|
||||||
assertTrue(nd[0] instanceof DeletedArea3DPtg);
|
assertTrue(nd[0] instanceof DeletedArea3DPtg);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Delete the 2nd sheet
|
// Delete the 2nd sheet
|
||||||
wb.removeSheetAt(1);
|
wb.removeSheetAt(1);
|
||||||
|
|
||||||
|
|
||||||
// Re-check
|
// Re-check
|
||||||
assertEquals(1, wb.getNumberOfNames());
|
assertEquals(1, wb.getNumberOfNames());
|
||||||
assertEquals(2, wb.getNumberOfSheets());
|
assertEquals(2, wb.getNumberOfSheets());
|
||||||
|
|
||||||
for(int i=0; i<w.getNumNames(); i++) {
|
for(int i=0; i<w.getNumNames(); i++) {
|
||||||
NameRecord r = w.getNameRecord(i);
|
NameRecord r = w.getNameRecord(i);
|
||||||
assertTrue(r.getSheetNumber() <= wb.getNumberOfSheets());
|
assertTrue(r.getSheetNumber() <= wb.getNumberOfSheets());
|
||||||
|
|
||||||
Ptg[] nd = r.getNameDefinition();
|
Ptg[] nd = r.getNameDefinition();
|
||||||
assertEquals(1, nd.length);
|
assertEquals(1, nd.length);
|
||||||
assertTrue(nd[0] instanceof DeletedArea3DPtg);
|
assertTrue(nd[0] instanceof DeletedArea3DPtg);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Save and re-load
|
// Save and re-load
|
||||||
wb = writeOutAndReadBack(wb);
|
wb = writeOutAndReadBack(wb);
|
||||||
w = wb.getWorkbook();
|
w = wb.getWorkbook();
|
||||||
|
|
||||||
assertEquals(1, wb.getNumberOfNames());
|
assertEquals(1, wb.getNumberOfNames());
|
||||||
assertEquals(2, wb.getNumberOfSheets());
|
assertEquals(2, wb.getNumberOfSheets());
|
||||||
|
|
||||||
for(int i=0; i<w.getNumNames(); i++) {
|
for(int i=0; i<w.getNumNames(); i++) {
|
||||||
NameRecord r = w.getNameRecord(i);
|
NameRecord r = w.getNameRecord(i);
|
||||||
assertTrue(r.getSheetNumber() <= wb.getNumberOfSheets());
|
assertTrue(r.getSheetNumber() <= wb.getNumberOfSheets());
|
||||||
|
|
||||||
Ptg[] nd = r.getNameDefinition();
|
Ptg[] nd = r.getNameDefinition();
|
||||||
assertEquals(1, nd.length);
|
assertEquals(1, nd.length);
|
||||||
assertTrue(nd[0] instanceof DeletedArea3DPtg);
|
assertTrue(nd[0] instanceof DeletedArea3DPtg);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Test that fonts get added properly
|
* Test that fonts get added properly
|
||||||
*/
|
*/
|
||||||
public void test45338() {
|
public void test45338() {
|
||||||
HSSFWorkbook wb = new HSSFWorkbook();
|
HSSFWorkbook wb = new HSSFWorkbook();
|
||||||
assertEquals(4, wb.getNumberOfFonts());
|
assertEquals(4, wb.getNumberOfFonts());
|
||||||
|
|
||||||
HSSFSheet s = wb.createSheet();
|
HSSFSheet s = wb.createSheet();
|
||||||
s.createRow(0);
|
s.createRow(0);
|
||||||
s.createRow(1);
|
s.createRow(1);
|
||||||
HSSFCell c1 = s.getRow(0).createCell(0);
|
HSSFCell c1 = s.getRow(0).createCell(0);
|
||||||
HSSFCell c2 = s.getRow(1).createCell(0);
|
HSSFCell c2 = s.getRow(1).createCell(0);
|
||||||
|
|
||||||
assertEquals(4, wb.getNumberOfFonts());
|
assertEquals(4, wb.getNumberOfFonts());
|
||||||
|
|
||||||
HSSFFont f1 = wb.getFontAt((short)0);
|
HSSFFont f1 = wb.getFontAt((short)0);
|
||||||
assertEquals(400, f1.getBoldweight());
|
assertEquals(400, f1.getBoldweight());
|
||||||
|
|
||||||
// Check that asking for the same font
|
// Check that asking for the same font
|
||||||
// multiple times gives you the same thing.
|
// multiple times gives you the same thing.
|
||||||
// Otherwise, our tests wouldn't work!
|
// Otherwise, our tests wouldn't work!
|
||||||
|
@ -1094,22 +1094,22 @@ public final class TestBugs extends TestCase {
|
||||||
!=
|
!=
|
||||||
wb.getFontAt((short)2)
|
wb.getFontAt((short)2)
|
||||||
);
|
);
|
||||||
|
|
||||||
// Look for a new font we have
|
// Look for a new font we have
|
||||||
// yet to add
|
// yet to add
|
||||||
assertNull(
|
assertNull(
|
||||||
wb.findFont(
|
wb.findFont(
|
||||||
(short)11, (short)123, (short)22,
|
(short)11, (short)123, (short)22,
|
||||||
"Thingy", false, true, (short)2, (byte)2
|
"Thingy", false, true, (short)2, (byte)2
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
HSSFFont nf = wb.createFont();
|
HSSFFont nf = wb.createFont();
|
||||||
assertEquals(5, wb.getNumberOfFonts());
|
assertEquals(5, wb.getNumberOfFonts());
|
||||||
|
|
||||||
assertEquals(5, nf.getIndex());
|
assertEquals(5, nf.getIndex());
|
||||||
assertEquals(nf, wb.getFontAt((short)5));
|
assertEquals(nf, wb.getFontAt((short)5));
|
||||||
|
|
||||||
nf.setBoldweight((short)11);
|
nf.setBoldweight((short)11);
|
||||||
nf.setColor((short)123);
|
nf.setColor((short)123);
|
||||||
nf.setFontHeight((short)22);
|
nf.setFontHeight((short)22);
|
||||||
|
@ -1118,32 +1118,32 @@ public final class TestBugs extends TestCase {
|
||||||
nf.setStrikeout(true);
|
nf.setStrikeout(true);
|
||||||
nf.setTypeOffset((short)2);
|
nf.setTypeOffset((short)2);
|
||||||
nf.setUnderline((byte)2);
|
nf.setUnderline((byte)2);
|
||||||
|
|
||||||
assertEquals(5, wb.getNumberOfFonts());
|
assertEquals(5, wb.getNumberOfFonts());
|
||||||
assertEquals(nf, wb.getFontAt((short)5));
|
assertEquals(nf, wb.getFontAt((short)5));
|
||||||
|
|
||||||
// Find it now
|
// Find it now
|
||||||
assertNotNull(
|
assertNotNull(
|
||||||
wb.findFont(
|
wb.findFont(
|
||||||
(short)11, (short)123, (short)22,
|
(short)11, (short)123, (short)22,
|
||||||
"Thingy", false, true, (short)2, (byte)2
|
"Thingy", false, true, (short)2, (byte)2
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
assertEquals(
|
assertEquals(
|
||||||
5,
|
5,
|
||||||
wb.findFont(
|
wb.findFont(
|
||||||
(short)11, (short)123, (short)22,
|
(short)11, (short)123, (short)22,
|
||||||
"Thingy", false, true, (short)2, (byte)2
|
"Thingy", false, true, (short)2, (byte)2
|
||||||
).getIndex()
|
).getIndex()
|
||||||
);
|
);
|
||||||
assertEquals(nf,
|
assertEquals(nf,
|
||||||
wb.findFont(
|
wb.findFont(
|
||||||
(short)11, (short)123, (short)22,
|
(short)11, (short)123, (short)22,
|
||||||
"Thingy", false, true, (short)2, (byte)2
|
"Thingy", false, true, (short)2, (byte)2
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* From the mailing list - ensure we can handle a formula
|
* From the mailing list - ensure we can handle a formula
|
||||||
* containing a zip code, eg ="70164"
|
* containing a zip code, eg ="70164"
|
||||||
|
@ -1160,63 +1160,59 @@ public final class TestBugs extends TestCase {
|
||||||
c1.setCellFormula("70164");
|
c1.setCellFormula("70164");
|
||||||
c2.setCellFormula("\"70164\"");
|
c2.setCellFormula("\"70164\"");
|
||||||
c3.setCellFormula("\"90210\"");
|
c3.setCellFormula("\"90210\"");
|
||||||
|
|
||||||
// Check the formulas
|
// Check the formulas
|
||||||
assertEquals("70164.0", c1.getCellFormula());
|
assertEquals("70164.0", c1.getCellFormula());
|
||||||
assertEquals("\"70164\"", c2.getCellFormula());
|
assertEquals("\"70164\"", c2.getCellFormula());
|
||||||
|
|
||||||
// And check the values - blank
|
// And check the values - blank
|
||||||
assertEquals(0.0, c1.getNumericCellValue(), 0.00001);
|
confirmCachedValue(0.0, c1);
|
||||||
assertEquals("", c1.getRichStringCellValue().getString());
|
confirmCachedValue(0.0, c2);
|
||||||
assertEquals(0.0, c2.getNumericCellValue(), 0.00001);
|
confirmCachedValue(0.0, c3);
|
||||||
assertEquals("", c2.getRichStringCellValue().getString());
|
|
||||||
assertEquals(0.0, c3.getNumericCellValue(), 0.00001);
|
|
||||||
assertEquals("", c3.getRichStringCellValue().getString());
|
|
||||||
|
|
||||||
// Try changing the cached value on one of the string
|
// Try changing the cached value on one of the string
|
||||||
// formula cells, so we can see it updates properly
|
// formula cells, so we can see it updates properly
|
||||||
c3.setCellValue(new HSSFRichTextString("test"));
|
c3.setCellValue(new HSSFRichTextString("test"));
|
||||||
assertEquals(0.0, c3.getNumericCellValue(), 0.00001);
|
confirmCachedValue("test", c3);
|
||||||
assertEquals("test", c3.getRichStringCellValue().getString());
|
try {
|
||||||
|
c3.getNumericCellValue();
|
||||||
|
throw new AssertionFailedError("exception should have been thrown");
|
||||||
|
} catch (IllegalStateException e) {
|
||||||
|
assertEquals("Cannot get a numeric value from a text formula cell", e.getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// Now evaluate, they should all be changed
|
// Now evaluate, they should all be changed
|
||||||
HSSFFormulaEvaluator eval = new HSSFFormulaEvaluator(s, wb);
|
HSSFFormulaEvaluator eval = new HSSFFormulaEvaluator(s, wb);
|
||||||
eval.evaluateFormulaCell(c1);
|
eval.evaluateFormulaCell(c1);
|
||||||
eval.evaluateFormulaCell(c2);
|
eval.evaluateFormulaCell(c2);
|
||||||
eval.evaluateFormulaCell(c3);
|
eval.evaluateFormulaCell(c3);
|
||||||
|
|
||||||
// Check that the cells now contain
|
// Check that the cells now contain
|
||||||
// the correct values
|
// the correct values
|
||||||
assertEquals(70164.0, c1.getNumericCellValue(), 0.00001);
|
confirmCachedValue(70164.0, c1);
|
||||||
assertEquals("", c1.getRichStringCellValue().getString());
|
confirmCachedValue("70164", c2);
|
||||||
assertEquals(0.0, c2.getNumericCellValue(), 0.00001);
|
confirmCachedValue("90210", c3);
|
||||||
assertEquals("70164", c2.getRichStringCellValue().getString());
|
|
||||||
assertEquals(0.0, c3.getNumericCellValue(), 0.00001);
|
|
||||||
assertEquals("90210", c3.getRichStringCellValue().getString());
|
|
||||||
|
|
||||||
|
|
||||||
// Write and read
|
// Write and read
|
||||||
HSSFWorkbook nwb = writeOutAndReadBack(wb);
|
HSSFWorkbook nwb = writeOutAndReadBack(wb);
|
||||||
HSSFSheet ns = nwb.getSheetAt(0);
|
HSSFSheet ns = nwb.getSheetAt(0);
|
||||||
HSSFCell nc1 = ns.getRow(0).getCell(0);
|
HSSFCell nc1 = ns.getRow(0).getCell(0);
|
||||||
HSSFCell nc2 = ns.getRow(0).getCell(1);
|
HSSFCell nc2 = ns.getRow(0).getCell(1);
|
||||||
HSSFCell nc3 = ns.getRow(0).getCell(2);
|
HSSFCell nc3 = ns.getRow(0).getCell(2);
|
||||||
|
|
||||||
// Re-check
|
// Re-check
|
||||||
assertEquals(70164.0, nc1.getNumericCellValue(), 0.00001);
|
confirmCachedValue(70164.0, nc1);
|
||||||
assertEquals("", nc1.getRichStringCellValue().getString());
|
confirmCachedValue("70164", nc2);
|
||||||
assertEquals(0.0, nc2.getNumericCellValue(), 0.00001);
|
confirmCachedValue("90210", nc3);
|
||||||
assertEquals("70164", nc2.getRichStringCellValue().getString());
|
|
||||||
assertEquals(0.0, nc3.getNumericCellValue(), 0.00001);
|
|
||||||
assertEquals("90210", nc3.getRichStringCellValue().getString());
|
|
||||||
|
|
||||||
CellValueRecordInterface[] cvrs = ns.getSheet().getValueRecords();
|
CellValueRecordInterface[] cvrs = ns.getSheet().getValueRecords();
|
||||||
for (int i = 0; i < cvrs.length; i++) {
|
for (int i = 0; i < cvrs.length; i++) {
|
||||||
CellValueRecordInterface cvr = cvrs[i];
|
CellValueRecordInterface cvr = cvrs[i];
|
||||||
if(cvr instanceof FormulaRecordAggregate) {
|
if(cvr instanceof FormulaRecordAggregate) {
|
||||||
FormulaRecordAggregate fr = (FormulaRecordAggregate)cvr;
|
FormulaRecordAggregate fr = (FormulaRecordAggregate)cvr;
|
||||||
|
|
||||||
if(i == 0) {
|
if(i == 0) {
|
||||||
assertEquals(70164.0, fr.getFormulaRecord().getValue(), 0.0001);
|
assertEquals(70164.0, fr.getFormulaRecord().getValue(), 0.0001);
|
||||||
assertNull(fr.getStringRecord());
|
assertNull(fr.getStringRecord());
|
||||||
|
@ -1233,7 +1229,18 @@ public final class TestBugs extends TestCase {
|
||||||
}
|
}
|
||||||
assertEquals(3, cvrs.length);
|
assertEquals(3, cvrs.length);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static void confirmCachedValue(double expectedValue, HSSFCell cell) {
|
||||||
|
assertEquals(HSSFCell.CELL_TYPE_FORMULA, cell.getCellType());
|
||||||
|
assertEquals(HSSFCell.CELL_TYPE_NUMERIC, cell.getCachedFormulaResultType());
|
||||||
|
assertEquals(expectedValue, cell.getNumericCellValue(), 0.0);
|
||||||
|
}
|
||||||
|
private static void confirmCachedValue(String expectedValue, HSSFCell cell) {
|
||||||
|
assertEquals(HSSFCell.CELL_TYPE_FORMULA, cell.getCellType());
|
||||||
|
assertEquals(HSSFCell.CELL_TYPE_STRING, cell.getCachedFormulaResultType());
|
||||||
|
assertEquals(expectedValue, cell.getRichStringCellValue().getString());
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Problem with "Vector Rows", eg a whole
|
* Problem with "Vector Rows", eg a whole
|
||||||
* column which is set to the result of
|
* column which is set to the result of
|
||||||
|
@ -1242,37 +1249,37 @@ public final class TestBugs extends TestCase {
|
||||||
* {=sin(B1:B9){9,1)[rownum][0]
|
* {=sin(B1:B9){9,1)[rownum][0]
|
||||||
* In this sample file, the vector column
|
* In this sample file, the vector column
|
||||||
* is C, and the data column is B.
|
* is C, and the data column is B.
|
||||||
*
|
*
|
||||||
* For now, blows up with an exception from ExtPtg
|
* For now, blows up with an exception from ExtPtg
|
||||||
* Expected ExpPtg to be converted from Shared to Non-Shared...
|
* Expected ExpPtg to be converted from Shared to Non-Shared...
|
||||||
*/
|
*/
|
||||||
public void DISABLEDtest43623() {
|
public void DISABLEDtest43623() {
|
||||||
HSSFWorkbook wb = openSample("43623.xls");
|
HSSFWorkbook wb = openSample("43623.xls");
|
||||||
assertEquals(1, wb.getNumberOfSheets());
|
assertEquals(1, wb.getNumberOfSheets());
|
||||||
|
|
||||||
HSSFSheet s1 = wb.getSheetAt(0);
|
HSSFSheet s1 = wb.getSheetAt(0);
|
||||||
|
|
||||||
HSSFCell c1 = s1.getRow(0).getCell(2);
|
HSSFCell c1 = s1.getRow(0).getCell(2);
|
||||||
HSSFCell c2 = s1.getRow(1).getCell(2);
|
HSSFCell c2 = s1.getRow(1).getCell(2);
|
||||||
HSSFCell c3 = s1.getRow(2).getCell(2);
|
HSSFCell c3 = s1.getRow(2).getCell(2);
|
||||||
|
|
||||||
// These formula contents are a guess...
|
// These formula contents are a guess...
|
||||||
assertEquals("{=sin(B1:B9){9,1)[0][0]", c1.getCellFormula());
|
assertEquals("{=sin(B1:B9){9,1)[0][0]", c1.getCellFormula());
|
||||||
assertEquals("{=sin(B1:B9){9,1)[1][0]", c2.getCellFormula());
|
assertEquals("{=sin(B1:B9){9,1)[1][0]", c2.getCellFormula());
|
||||||
assertEquals("{=sin(B1:B9){9,1)[2][0]", c3.getCellFormula());
|
assertEquals("{=sin(B1:B9){9,1)[2][0]", c3.getCellFormula());
|
||||||
|
|
||||||
// Save and re-open, ensure it still works
|
// Save and re-open, ensure it still works
|
||||||
HSSFWorkbook nwb = writeOutAndReadBack(wb);
|
HSSFWorkbook nwb = writeOutAndReadBack(wb);
|
||||||
HSSFSheet ns1 = nwb.getSheetAt(0);
|
HSSFSheet ns1 = nwb.getSheetAt(0);
|
||||||
HSSFCell nc1 = ns1.getRow(0).getCell(2);
|
HSSFCell nc1 = ns1.getRow(0).getCell(2);
|
||||||
HSSFCell nc2 = ns1.getRow(1).getCell(2);
|
HSSFCell nc2 = ns1.getRow(1).getCell(2);
|
||||||
HSSFCell nc3 = ns1.getRow(2).getCell(2);
|
HSSFCell nc3 = ns1.getRow(2).getCell(2);
|
||||||
|
|
||||||
assertEquals("{=sin(B1:B9){9,1)[0][0]", nc1.getCellFormula());
|
assertEquals("{=sin(B1:B9){9,1)[0][0]", nc1.getCellFormula());
|
||||||
assertEquals("{=sin(B1:B9){9,1)[1][0]", nc2.getCellFormula());
|
assertEquals("{=sin(B1:B9){9,1)[1][0]", nc2.getCellFormula());
|
||||||
assertEquals("{=sin(B1:B9){9,1)[2][0]", nc3.getCellFormula());
|
assertEquals("{=sin(B1:B9){9,1)[2][0]", nc3.getCellFormula());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* People are all getting confused about the last
|
* People are all getting confused about the last
|
||||||
* row and cell number
|
* row and cell number
|
||||||
|
@ -1280,48 +1287,48 @@ public final class TestBugs extends TestCase {
|
||||||
public void test30635() {
|
public void test30635() {
|
||||||
HSSFWorkbook wb = new HSSFWorkbook();
|
HSSFWorkbook wb = new HSSFWorkbook();
|
||||||
HSSFSheet s = wb.createSheet();
|
HSSFSheet s = wb.createSheet();
|
||||||
|
|
||||||
// No rows, everything is 0
|
// No rows, everything is 0
|
||||||
assertEquals(0, s.getFirstRowNum());
|
assertEquals(0, s.getFirstRowNum());
|
||||||
assertEquals(0, s.getLastRowNum());
|
assertEquals(0, s.getLastRowNum());
|
||||||
assertEquals(0, s.getPhysicalNumberOfRows());
|
assertEquals(0, s.getPhysicalNumberOfRows());
|
||||||
|
|
||||||
// One row, most things are 0, physical is 1
|
// One row, most things are 0, physical is 1
|
||||||
s.createRow(0);
|
s.createRow(0);
|
||||||
assertEquals(0, s.getFirstRowNum());
|
assertEquals(0, s.getFirstRowNum());
|
||||||
assertEquals(0, s.getLastRowNum());
|
assertEquals(0, s.getLastRowNum());
|
||||||
assertEquals(1, s.getPhysicalNumberOfRows());
|
assertEquals(1, s.getPhysicalNumberOfRows());
|
||||||
|
|
||||||
// And another, things change
|
// And another, things change
|
||||||
s.createRow(4);
|
s.createRow(4);
|
||||||
assertEquals(0, s.getFirstRowNum());
|
assertEquals(0, s.getFirstRowNum());
|
||||||
assertEquals(4, s.getLastRowNum());
|
assertEquals(4, s.getLastRowNum());
|
||||||
assertEquals(2, s.getPhysicalNumberOfRows());
|
assertEquals(2, s.getPhysicalNumberOfRows());
|
||||||
|
|
||||||
|
|
||||||
// Now start on cells
|
// Now start on cells
|
||||||
HSSFRow r = s.getRow(0);
|
HSSFRow r = s.getRow(0);
|
||||||
assertEquals(-1, r.getFirstCellNum());
|
assertEquals(-1, r.getFirstCellNum());
|
||||||
assertEquals(-1, r.getLastCellNum());
|
assertEquals(-1, r.getLastCellNum());
|
||||||
assertEquals(0, r.getPhysicalNumberOfCells());
|
assertEquals(0, r.getPhysicalNumberOfCells());
|
||||||
|
|
||||||
// Add a cell, things move off -1
|
// Add a cell, things move off -1
|
||||||
r.createCell(0);
|
r.createCell(0);
|
||||||
assertEquals(0, r.getFirstCellNum());
|
assertEquals(0, r.getFirstCellNum());
|
||||||
assertEquals(1, r.getLastCellNum()); // last cell # + 1
|
assertEquals(1, r.getLastCellNum()); // last cell # + 1
|
||||||
assertEquals(1, r.getPhysicalNumberOfCells());
|
assertEquals(1, r.getPhysicalNumberOfCells());
|
||||||
|
|
||||||
r.createCell(1);
|
r.createCell(1);
|
||||||
assertEquals(0, r.getFirstCellNum());
|
assertEquals(0, r.getFirstCellNum());
|
||||||
assertEquals(2, r.getLastCellNum()); // last cell # + 1
|
assertEquals(2, r.getLastCellNum()); // last cell # + 1
|
||||||
assertEquals(2, r.getPhysicalNumberOfCells());
|
assertEquals(2, r.getPhysicalNumberOfCells());
|
||||||
|
|
||||||
r.createCell(4);
|
r.createCell(4);
|
||||||
assertEquals(0, r.getFirstCellNum());
|
assertEquals(0, r.getFirstCellNum());
|
||||||
assertEquals(5, r.getLastCellNum()); // last cell # + 1
|
assertEquals(5, r.getLastCellNum()); // last cell # + 1
|
||||||
assertEquals(3, r.getPhysicalNumberOfCells());
|
assertEquals(3, r.getPhysicalNumberOfCells());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Data Tables - ptg 0x2
|
* Data Tables - ptg 0x2
|
||||||
*/
|
*/
|
||||||
|
@ -1330,25 +1337,25 @@ public final class TestBugs extends TestCase {
|
||||||
HSSFSheet s;
|
HSSFSheet s;
|
||||||
HSSFRow r;
|
HSSFRow r;
|
||||||
HSSFCell c;
|
HSSFCell c;
|
||||||
|
|
||||||
// Check the contents of the formulas
|
// Check the contents of the formulas
|
||||||
|
|
||||||
// E4 to G9 of sheet 4 make up the table
|
// E4 to G9 of sheet 4 make up the table
|
||||||
s = wb.getSheet("OneVariable Table Completed");
|
s = wb.getSheet("OneVariable Table Completed");
|
||||||
r = s.getRow(3);
|
r = s.getRow(3);
|
||||||
c = r.getCell(4);
|
c = r.getCell(4);
|
||||||
assertEquals(HSSFCell.CELL_TYPE_FORMULA, c.getCellType());
|
assertEquals(HSSFCell.CELL_TYPE_FORMULA, c.getCellType());
|
||||||
|
|
||||||
// TODO - check the formula once tables and
|
// TODO - check the formula once tables and
|
||||||
// arrays are properly supported
|
// arrays are properly supported
|
||||||
|
|
||||||
|
|
||||||
// E4 to H9 of sheet 5 make up the table
|
// E4 to H9 of sheet 5 make up the table
|
||||||
s = wb.getSheet("TwoVariable Table Example");
|
s = wb.getSheet("TwoVariable Table Example");
|
||||||
r = s.getRow(3);
|
r = s.getRow(3);
|
||||||
c = r.getCell(4);
|
c = r.getCell(4);
|
||||||
assertEquals(HSSFCell.CELL_TYPE_FORMULA, c.getCellType());
|
assertEquals(HSSFCell.CELL_TYPE_FORMULA, c.getCellType());
|
||||||
|
|
||||||
// TODO - check the formula once tables and
|
// TODO - check the formula once tables and
|
||||||
// arrays are properly supported
|
// arrays are properly supported
|
||||||
}
|
}
|
||||||
|
@ -1361,7 +1368,7 @@ public final class TestBugs extends TestCase {
|
||||||
HSSFSheet sh = wb.getSheetAt(0);
|
HSSFSheet sh = wb.getSheetAt(0);
|
||||||
for(short i=0; i < 30; i++) sh.autoSizeColumn(i);
|
for(short i=0; i < 30; i++) sh.autoSizeColumn(i);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* We used to add too many UncalcRecords to sheets
|
* We used to add too many UncalcRecords to sheets
|
||||||
* with diagrams on. Don't any more
|
* with diagrams on. Don't any more
|
||||||
|
@ -1371,41 +1378,41 @@ public final class TestBugs extends TestCase {
|
||||||
wb.getSheetAt(0).setForceFormulaRecalculation(true);
|
wb.getSheetAt(0).setForceFormulaRecalculation(true);
|
||||||
wb.getSheetAt(1).setForceFormulaRecalculation(false);
|
wb.getSheetAt(1).setForceFormulaRecalculation(false);
|
||||||
wb.getSheetAt(2).setForceFormulaRecalculation(true);
|
wb.getSheetAt(2).setForceFormulaRecalculation(true);
|
||||||
|
|
||||||
// Write out and back in again
|
// Write out and back in again
|
||||||
// This used to break
|
// This used to break
|
||||||
HSSFWorkbook nwb = writeOutAndReadBack(wb);
|
HSSFWorkbook nwb = writeOutAndReadBack(wb);
|
||||||
|
|
||||||
// Check now set as it should be
|
// Check now set as it should be
|
||||||
assertTrue(nwb.getSheetAt(0).getForceFormulaRecalculation());
|
assertTrue(nwb.getSheetAt(0).getForceFormulaRecalculation());
|
||||||
assertFalse(nwb.getSheetAt(1).getForceFormulaRecalculation());
|
assertFalse(nwb.getSheetAt(1).getForceFormulaRecalculation());
|
||||||
assertTrue(nwb.getSheetAt(2).getForceFormulaRecalculation());
|
assertTrue(nwb.getSheetAt(2).getForceFormulaRecalculation());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Very hidden sheets not displaying as such
|
* Very hidden sheets not displaying as such
|
||||||
*/
|
*/
|
||||||
public void test45761() {
|
public void test45761() {
|
||||||
HSSFWorkbook wb = openSample("45761.xls");
|
HSSFWorkbook wb = openSample("45761.xls");
|
||||||
assertEquals(3, wb.getNumberOfSheets());
|
assertEquals(3, wb.getNumberOfSheets());
|
||||||
|
|
||||||
assertFalse(wb.isSheetHidden(0));
|
assertFalse(wb.isSheetHidden(0));
|
||||||
assertFalse(wb.isSheetVeryHidden(0));
|
assertFalse(wb.isSheetVeryHidden(0));
|
||||||
assertTrue(wb.isSheetHidden(1));
|
assertTrue(wb.isSheetHidden(1));
|
||||||
assertFalse(wb.isSheetVeryHidden(1));
|
assertFalse(wb.isSheetVeryHidden(1));
|
||||||
assertFalse(wb.isSheetHidden(2));
|
assertFalse(wb.isSheetHidden(2));
|
||||||
assertTrue(wb.isSheetVeryHidden(2));
|
assertTrue(wb.isSheetVeryHidden(2));
|
||||||
|
|
||||||
// Change 0 to be very hidden, and re-load
|
// Change 0 to be very hidden, and re-load
|
||||||
wb.setSheetHidden(0, 2);
|
wb.setSheetHidden(0, 2);
|
||||||
|
|
||||||
HSSFWorkbook nwb = writeOutAndReadBack(wb);
|
HSSFWorkbook nwb = writeOutAndReadBack(wb);
|
||||||
|
|
||||||
assertFalse(nwb.isSheetHidden(0));
|
assertFalse(nwb.isSheetHidden(0));
|
||||||
assertTrue(nwb.isSheetVeryHidden(0));
|
assertTrue(nwb.isSheetVeryHidden(0));
|
||||||
assertTrue(nwb.isSheetHidden(1));
|
assertTrue(nwb.isSheetHidden(1));
|
||||||
assertFalse(nwb.isSheetVeryHidden(1));
|
assertFalse(nwb.isSheetVeryHidden(1));
|
||||||
assertFalse(nwb.isSheetHidden(2));
|
assertFalse(nwb.isSheetHidden(2));
|
||||||
assertTrue(nwb.isSheetVeryHidden(2));
|
assertTrue(nwb.isSheetVeryHidden(2));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue