Patch to support UncalcedRecord and usermodel code for it, to indicate formulas on a sheet need recalculating (from bug #44233)

git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@612445 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Nick Burch 2008-01-16 13:14:31 +00:00
parent 18a4647b24
commit 33602b0c80
9 changed files with 224 additions and 7 deletions

View File

@ -36,6 +36,7 @@
<!-- Don't forget to update status.xml too! --> <!-- Don't forget to update status.xml too! -->
<release version="3.0.2-FINAL" date="2008-??-??"> <release version="3.0.2-FINAL" date="2008-??-??">
<action dev="POI-DEVELOPERS" type="add">44233 - Support for getting and setting a flag on the sheet, which tells excel to re-calculate all formulas on it at next reload</action>
<action dev="POI-DEVELOPERS" type="fix">44201 - Enable cloning of sheets with data validation rules</action> <action dev="POI-DEVELOPERS" type="fix">44201 - Enable cloning of sheets with data validation rules</action>
<action dev="POI-DEVELOPERS" type="fix">44200 - Enable cloning of sheets with notes</action> <action dev="POI-DEVELOPERS" type="fix">44200 - Enable cloning of sheets with notes</action>
<action dev="POI-DEVELOPERS" type="add">43008 - Add a moveCell method to HSSFRow, and deprecate setCellNum(), which didn't update things properly</action> <action dev="POI-DEVELOPERS" type="add">43008 - Add a moveCell method to HSSFRow, and deprecate setCellNum(), which didn't update things properly</action>

View File

@ -33,6 +33,7 @@
<!-- Don't forget to update changes.xml too! --> <!-- Don't forget to update changes.xml too! -->
<changes> <changes>
<release version="3.0.2-FINAL" date="2008-??-??"> <release version="3.0.2-FINAL" date="2008-??-??">
<action dev="POI-DEVELOPERS" type="add">44233 - Support for getting and setting a flag on the sheet, which tells excel to re-calculate all formulas on it at next reload</action>
<action dev="POI-DEVELOPERS" type="fix">44201 - Enable cloning of sheets with data validation rules</action> <action dev="POI-DEVELOPERS" type="fix">44201 - Enable cloning of sheets with data validation rules</action>
<action dev="POI-DEVELOPERS" type="fix">44200 - Enable cloning of sheets with notes</action> <action dev="POI-DEVELOPERS" type="fix">44200 - Enable cloning of sheets with notes</action>
<action dev="POI-DEVELOPERS" type="add">43008 - Add a moveCell method to HSSFRow, and deprecate setCellNum(), which didn't update things properly</action> <action dev="POI-DEVELOPERS" type="add">43008 - Add a moveCell method to HSSFRow, and deprecate setCellNum(), which didn't update things properly</action>

View File

@ -97,6 +97,8 @@ public class Sheet implements Model
protected ScenarioProtectRecord scenprotect = null; protected ScenarioProtectRecord scenprotect = null;
protected PasswordRecord password = null; protected PasswordRecord password = null;
/** Add an UncalcedRecord if not true indicating formulas have not been calculated */
protected boolean uncalced = false;
public static final byte PANE_LOWER_RIGHT = (byte)0; public static final byte PANE_LOWER_RIGHT = (byte)0;
public static final byte PANE_UPPER_RIGHT = (byte)1; public static final byte PANE_UPPER_RIGHT = (byte)1;
@ -161,6 +163,9 @@ public class Sheet implements Model
break; break;
} }
} }
else if (rec.getSid() == UncalcedRecord.sid) {
retval.uncalced = true;
}
else if (rec.getSid() == DimensionsRecord.sid) else if (rec.getSid() == DimensionsRecord.sid)
{ {
// Make a columns aggregate if one hasn't ready been created. // Make a columns aggregate if one hasn't ready been created.
@ -736,6 +741,12 @@ public class Sheet implements Model
{ {
Record record = (( Record ) records.get(k)); Record record = (( Record ) records.get(k));
// Don't write out UncalcedRecord entries, as
// we handle those specially just below
if (record instanceof UncalcedRecord) {
continue;
}
// Once the rows have been found in the list of records, start // Once the rows have been found in the list of records, start
// writing out the blocked row information. This includes the DBCell references // writing out the blocked row information. This includes the DBCell references
if (record instanceof RowRecordsAggregate) { if (record instanceof RowRecordsAggregate) {
@ -745,8 +756,14 @@ public class Sheet implements Model
} else { } else {
pos += record.serialize(pos, data ); // rec.length; pos += record.serialize(pos, data ); // rec.length;
} }
// If the BOF record was just serialized then add the IndexRecord // If the BOF record was just serialized then add the IndexRecord
if (record.getSid() == BOFRecord.sid) { if (record.getSid() == BOFRecord.sid) {
// Add an optional UncalcedRecord
if (uncalced) {
UncalcedRecord rec = new UncalcedRecord();
pos += rec.serialize(pos, data);
}
//Can there be more than one BOF for a sheet? If not then we can //Can there be more than one BOF for a sheet? If not then we can
//remove this guard. So be safe it is left here. //remove this guard. So be safe it is left here.
if (rows != null && !haveSerializedIndex) { if (rows != null && !haveSerializedIndex) {
@ -2184,6 +2201,11 @@ public class Sheet implements Model
retval += 2; retval += 2;
} }
} }
// Add space for UncalcedRecord
if (uncalced) {
retval += UncalcedRecord.getStaticRecordSize();
}
return retval; return retval;
} }
@ -2652,6 +2674,20 @@ public class Sheet implements Model
return windowTwo.getDisplayRowColHeadings(); return windowTwo.getDisplayRowColHeadings();
} }
/**
* @return whether an uncalced record must be inserted or not at generation
*/
public boolean getUncalced() {
return uncalced;
}
/**
* @param uncalced whether an uncalced record must be inserted or not at generation
*/
public void setUncalced(boolean uncalced) {
this.uncalced = uncalced;
}
/** /**
* Returns the array of margins. If not created, will create. * Returns the array of margins. If not created, will create.
* *

View File

@ -76,7 +76,7 @@ public class RecordFactory
WriteProtectRecord.class, FilePassRecord.class, PaneRecord.class, WriteProtectRecord.class, FilePassRecord.class, PaneRecord.class,
NoteRecord.class, ObjectProtectRecord.class, ScenarioProtectRecord.class, NoteRecord.class, ObjectProtectRecord.class, ScenarioProtectRecord.class,
FileSharingRecord.class, ChartTitleFormatRecord.class, FileSharingRecord.class, ChartTitleFormatRecord.class,
DVRecord.class, DVALRecord.class DVRecord.class, DVALRecord.class, UncalcedRecord.class
}; };
} }
private static Map recordsMap = recordsToMap(records); private static Map recordsMap = recordsToMap(records);

View File

@ -0,0 +1,81 @@
/* ====================================================================
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
this work for additional information regarding copyright ownership.
The ASF licenses this file to You under the Apache License, Version 2.0
(the "License"); you may not use this file except in compliance with
the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
==================================================================== */
package org.apache.poi.hssf.record;
import org.apache.poi.util.LittleEndian;
/**
* Title: Uncalced Record
* <P>
* If this record occurs in the Worksheet Substream, it indicates that the formulas have not
* been recalculated before the document was saved.
*
* @author Olivier Leprince
*/
public class UncalcedRecord extends Record
{
public final static short sid = 0x5E;
/**
* Default constructor
*/
public UncalcedRecord() {
}
/**
* read constructor
*/
public UncalcedRecord(RecordInputStream in) {
super(in);
}
public short getSid() {
return sid;
}
protected void validateSid(short id) {
if (id != sid) {
throw new RecordFormatException("NOT AN UNCALCED RECORD");
}
}
protected void fillFields(RecordInputStream in) {
}
public String toString() {
StringBuffer buffer = new StringBuffer();
buffer.append("[UNCALCED]\n");
buffer.append("[/UNCALCED]\n");
return buffer.toString();
}
public int serialize(int offset, byte[] data) {
LittleEndian.putShort(data, 0 + offset, sid);
LittleEndian.putShort(data, 2 + offset, (short) 2);
LittleEndian.putShort(data, 4 + offset, (short) 0); // unused
return getRecordSize();
}
public int getRecordSize() {
return UncalcedRecord.getStaticRecordSize();
}
public static int getStaticRecordSize() {
return 6;
}
}

View File

@ -594,6 +594,26 @@ public class HSSFSheet
region.getColumnTo()); region.getColumnTo());
} }
/**
* Whether a record must be inserted or not at generation to indicate that
* formula must be recalculated when workbook is opened.
* @param value true if an uncalced record must be inserted or not at generation
*/
public void setForceFormulaRecalculation(boolean value)
{
sheet.setUncalced(value);
}
/**
* Whether a record must be inserted or not at generation to indicate that
* formula must be recalculated when workbook is opened.
* @return true if an uncalced record must be inserted or not at generation
*/
public boolean getForceFormulaRecalculation()
{
return sheet.getUncalced();
}
/** /**
* determines whether the output is vertically centered on the page. * determines whether the output is vertically centered on the page.
* @param value true to vertically center, false otherwise. * @param value true to vertically center, false otherwise.

View File

@ -19,14 +19,18 @@
package org.apache.poi.hssf.usermodel; package org.apache.poi.hssf.usermodel;
import java.io.*; import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import junit.framework.TestCase; import junit.framework.TestCase;
import org.apache.poi.hssf.model.Sheet; import org.apache.poi.hssf.model.Sheet;
import org.apache.poi.hssf.record.HCenterRecord; import org.apache.poi.hssf.record.HCenterRecord;
import org.apache.poi.hssf.record.ProtectRecord;
import org.apache.poi.hssf.record.PasswordRecord; import org.apache.poi.hssf.record.PasswordRecord;
import org.apache.poi.hssf.record.ProtectRecord;
import org.apache.poi.hssf.record.SCLRecord; import org.apache.poi.hssf.record.SCLRecord;
import org.apache.poi.hssf.record.VCenterRecord; import org.apache.poi.hssf.record.VCenterRecord;
import org.apache.poi.hssf.record.WSBoolRecord; import org.apache.poi.hssf.record.WSBoolRecord;
@ -790,6 +794,80 @@ public class TestHSSFSheet
assertTrue(sheet3.getColumnWidth((short)0) <= maxWithRow1And2); assertTrue(sheet3.getColumnWidth((short)0) <= maxWithRow1And2);
} }
/**
* Setting ForceFormulaRecalculation on sheets
*/
public void testForceRecalculation() throws Exception {
String filename = System.getProperty("HSSF.testdata.path");
filename = filename + "/UncalcedRecord.xls";
HSSFWorkbook workbook = new HSSFWorkbook(new FileInputStream(filename));
HSSFSheet sheet = workbook.getSheetAt(0);
HSSFSheet sheet2 = workbook.getSheetAt(0);
HSSFRow row = sheet.getRow(0);
row.createCell((short) 0).setCellValue(5);
row.createCell((short) 1).setCellValue(8);
assertFalse(sheet.getForceFormulaRecalculation());
assertFalse(sheet2.getForceFormulaRecalculation());
// Save and manually verify that on column C we have 0, value in template
File tempFile = new File(System.getProperty("java.io.tmpdir")+"/uncalced_err.xls" );
tempFile.delete();
FileOutputStream fout = new FileOutputStream( tempFile );
workbook.write( fout );
fout.close();
sheet.setForceFormulaRecalculation(true);
assertTrue(sheet.getForceFormulaRecalculation());
// Save and manually verify that on column C we have now 13, calculated value
tempFile = new File(System.getProperty("java.io.tmpdir")+"/uncalced_succ.xls" );
tempFile.delete();
fout = new FileOutputStream( tempFile );
workbook.write( fout );
fout.close();
// Try it can be opened
HSSFWorkbook wb2 = new HSSFWorkbook(new FileInputStream(tempFile));
// And check correct sheet settings found
sheet = wb2.getSheetAt(0);
sheet2 = wb2.getSheetAt(1);
assertTrue(sheet.getForceFormulaRecalculation());
assertFalse(sheet2.getForceFormulaRecalculation());
// Now turn if back off again
sheet.setForceFormulaRecalculation(false);
fout = new FileOutputStream( tempFile );
wb2.write( fout );
fout.close();
wb2 = new HSSFWorkbook(new FileInputStream(tempFile));
assertFalse(wb2.getSheetAt(0).getForceFormulaRecalculation());
assertFalse(wb2.getSheetAt(1).getForceFormulaRecalculation());
assertFalse(wb2.getSheetAt(2).getForceFormulaRecalculation());
// Now add a new sheet, and check things work
// with old ones unset, new one set
HSSFSheet s4 = wb2.createSheet();
s4.setForceFormulaRecalculation(true);
assertFalse(sheet.getForceFormulaRecalculation());
assertFalse(sheet2.getForceFormulaRecalculation());
assertTrue(s4.getForceFormulaRecalculation());
fout = new FileOutputStream( tempFile );
wb2.write( fout );
fout.close();
HSSFWorkbook wb3 = new HSSFWorkbook(new FileInputStream(tempFile));
assertFalse(wb3.getSheetAt(0).getForceFormulaRecalculation());
assertFalse(wb3.getSheetAt(1).getForceFormulaRecalculation());
assertFalse(wb3.getSheetAt(2).getForceFormulaRecalculation());
assertTrue(wb3.getSheetAt(3).getForceFormulaRecalculation());
}
public static void main(java.lang.String[] args) { public static void main(java.lang.String[] args) {
junit.textui.TestRunner.run(TestHSSFSheet.class); junit.textui.TestRunner.run(TestHSSFSheet.class);
} }