Merged revisions 668156-671000 via svnmerge from

https://svn.apache.org/repos/asf/poi/trunk

........
  r668257 | yegor | 2008-06-16 19:38:59 +0100 (Mon, 16 Jun 2008) | 1 line
  
  TextShape.getMarginLeft() returned incorrect value. Added a unit test for text margins.
........
  r668259 | yegor | 2008-06-16 19:40:51 +0100 (Mon, 16 Jun 2008) | 1 line
  
  patch from bug #45177: Remove GPL reference in NOTICE
........
  r669140 | nick | 2008-06-18 12:35:04 +0100 (Wed, 18 Jun 2008) | 1 line
  
  A partial fix for bug #30978, but something still remains, which seems to be related to changing the ptg
........
  r669456 | nick | 2008-06-19 12:47:48 +0100 (Thu, 19 Jun 2008) | 1 line
  
  Improved HWPF Range.replaceText, from N. Hira in bug #45001
........
  r669658 | josh | 2008-06-19 20:07:20 +0100 (Thu, 19 Jun 2008) | 1 line
  
  Fix for bug 45234 - Removed incorrect shared formula conversion in CFRuleRecord
........
  r669809 | josh | 2008-06-20 08:10:03 +0100 (Fri, 20 Jun 2008) | 1 line
  
  Fix for bug 30978 - small re-arrangement of class Ptg hierarchy for DeletedRef3DPtg and DeletedArea3DPtg. Similar to c664220
........
  r670190 | yegor | 2008-06-21 13:41:34 +0100 (Sat, 21 Jun 2008) | 1 line
  
  started a new section for poi-3.2 family, updated release date of 3.2-FINAL
........


git-svn-id: https://svn.apache.org/repos/asf/poi/branches/ooxml@674287 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Nick Burch 2008-07-06 12:11:37 +00:00
parent fb38bcb821
commit 695b85049d
22 changed files with 535 additions and 299 deletions

View File

@ -10,14 +10,6 @@ Common Public License Version 1.0:
http://www.opensource.org/licenses/cpl.php http://www.opensource.org/licenses/cpl.php
See http://www.junit.org/ See http://www.junit.org/
A single data file of the POI component HDGF is based on VSDump,
and is under the GNU General Public Licence version 3 (GPL v3):
http://gplv3.fsf.org/
Since this is a data file, and has no compiled version (the original
file is distributed in both source and binary versions), there should
be little difference in licencing requirements compared to the ASL.
See http://www.gnome.ru/projects/vsdump_en.html
The Office Open XML experimental support had additional dependencies, The Office Open XML experimental support had additional dependencies,
with their own licensing: with their own licensing:

View File

@ -45,7 +45,13 @@
<action dev="POI-DEVELOPERS" type="add">Created a common interface for handling PowerPoint files, irrespective of if they are .ppt or .pptx</action> <action dev="POI-DEVELOPERS" type="add">Created a common interface for handling PowerPoint files, irrespective of if they are .ppt or .pptx</action>
<action dev="POI-DEVELOPERS" type="add">Created a common interface for handling Excel files, irrespective of if they are .xls or .xlsx</action> <action dev="POI-DEVELOPERS" type="add">Created a common interface for handling Excel files, irrespective of if they are .xls or .xlsx</action>
</release> </release>
<release version="3.1-final" date="2008-06-??"> <release version="3.2-alpha1" date="2008-??-??">
<action dev="POI-DEVELOPERS" type="add"><!-- to keep forrest dtd quiet--></action>
</release>
<release version="3.1-final" date="2008-06-29">
<action dev="POI-DEVELOPERS" type="fix">30978 - Fixed re-serialization of tRefErr3d and tAreaErr3d</action>
<action dev="POI-DEVELOPERS" type="fix">45234 - Removed incorrect shared formula conversion in CFRuleRecord</action>
<action dev="POI-DEVELOPERS" type="fix">45001 - Improved HWPF Range.replaceText()</action>
<action dev="POI-DEVELOPERS" type="fix">44692 - Fixed HSSFPicture.resize() to properly resize pictures if the underlying columns/rows have modified size</action> <action dev="POI-DEVELOPERS" type="fix">44692 - Fixed HSSFPicture.resize() to properly resize pictures if the underlying columns/rows have modified size</action>
<action dev="POI-DEVELOPERS" type="add">Support custom image renderers in HSLF</action> <action dev="POI-DEVELOPERS" type="add">Support custom image renderers in HSLF</action>
<action dev="POI-DEVELOPERS" type="fix">Correctly increment the reference count of a blip when a picture is inserted</action> <action dev="POI-DEVELOPERS" type="fix">Correctly increment the reference count of a blip when a picture is inserted</action>

View File

@ -42,7 +42,13 @@
<action dev="POI-DEVELOPERS" type="add">Created a common interface for handling PowerPoint files, irrespective of if they are .ppt or .pptx</action> <action dev="POI-DEVELOPERS" type="add">Created a common interface for handling PowerPoint files, irrespective of if they are .ppt or .pptx</action>
<action dev="POI-DEVELOPERS" type="add">Created a common interface for handling Excel files, irrespective of if they are .xls or .xlsx</action> <action dev="POI-DEVELOPERS" type="add">Created a common interface for handling Excel files, irrespective of if they are .xls or .xlsx</action>
</release> </release>
<release version="3.1-final" date="2008-06-??"> <release version="3.2-alpha1" date="2008-??-??">
<action dev="POI-DEVELOPERS" type="add"><!-- to keep forrest dtd quiet--></action>
</release>
<release version="3.1-final" date="2008-06-29">
<action dev="POI-DEVELOPERS" type="fix">30978 - Fixed re-serialization of tRefErr3d and tAreaErr3d</action>
<action dev="POI-DEVELOPERS" type="fix">45234 - Removed incorrect shared formula conversion in CFRuleRecord</action>
<action dev="POI-DEVELOPERS" type="fix">45001 - Improved HWPF Range.replaceText()</action>
<action dev="POI-DEVELOPERS" type="fix">44692 - Fixed HSSFPicture.resize() to properly resize pictures if the underlying columns/rows have modified size</action> <action dev="POI-DEVELOPERS" type="fix">44692 - Fixed HSSFPicture.resize() to properly resize pictures if the underlying columns/rows have modified size</action>
<action dev="POI-DEVELOPERS" type="add">Support custom image renderers in HSLF</action> <action dev="POI-DEVELOPERS" type="add">Support custom image renderers in HSLF</action>
<action dev="POI-DEVELOPERS" type="fix">Correctly increment the reference count of a blip when a picture is inserted</action> <action dev="POI-DEVELOPERS" type="fix">Correctly increment the reference count of a blip when a picture is inserted</action>

View File

@ -604,8 +604,28 @@ public class Workbook implements Model
fixTabIdRecord(); fixTabIdRecord();
} }
// If we decide that we need to fix up // Within NameRecords, it's ok to have the formula
// NameRecords, do it here // part point at deleted sheets. It's also ok to
// have the ExternSheetNumber point at deleted
// sheets.
// However, the sheet index must be adjusted, or
// excel will break. (Sheet index is either 0 for
// global, or 1 based index to sheet)
int sheetNum1Based = sheetnum + 1;
for(int i=0; i<getNumNames(); i++) {
NameRecord nr = getNameRecord(i);
if(nr.getIndexToSheet() == sheetNum1Based) {
// Excel re-writes these to point to no sheet
nr.setEqualsToIndexToSheet((short)0);
} else if(nr.getIndexToSheet() > sheetNum1Based) {
// Bump down by one, so still points
// at the same sheet
nr.setEqualsToIndexToSheet((short)(
nr.getEqualsToIndexToSheet()-1
));
}
}
} }
/** /**

View File

@ -14,14 +14,10 @@
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.record; package org.apache.poi.hssf.record;
import java.util.Stack;
import org.apache.poi.hssf.model.FormulaParser; import org.apache.poi.hssf.model.FormulaParser;
import org.apache.poi.hssf.model.Workbook;
import org.apache.poi.hssf.record.cf.BorderFormatting; import org.apache.poi.hssf.record.cf.BorderFormatting;
import org.apache.poi.hssf.record.cf.FontFormatting; import org.apache.poi.hssf.record.cf.FontFormatting;
import org.apache.poi.hssf.record.cf.PatternFormatting; import org.apache.poi.hssf.record.cf.PatternFormatting;
@ -30,7 +26,6 @@ import org.apache.poi.hssf.usermodel.HSSFWorkbook;
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.LittleEndian; import org.apache.poi.util.LittleEndian;
import org.apache.poi.util.StringUtil;
/** /**
* Conditional Formatting Rule Record. * Conditional Formatting Rule Record.
@ -59,9 +54,6 @@ public final class CFRuleRecord extends Record
private byte field_2_comparison_operator; private byte field_2_comparison_operator;
private short field_3_formula1_len;
private short field_4_formula2_len;
private int field_5_options; private int field_5_options;
private static final BitField modificationBits = bf(0x003FFFFF); // Bits: font,align,bord,patt,prot private static final BitField modificationBits = bf(0x003FFFFF); // Bits: font,align,bord,patt,prot
@ -121,8 +113,6 @@ public final class CFRuleRecord extends Record
{ {
field_1_condition_type=conditionType; field_1_condition_type=conditionType;
field_2_comparison_operator=comparisonOperation; field_2_comparison_operator=comparisonOperation;
field_3_formula1_len = (short)0;
field_4_formula2_len = (short)0;
// Set modification flags to 1: by default options are not modified // Set modification flags to 1: by default options are not modified
field_5_options = modificationBits.setValue(field_5_options, -1); field_5_options = modificationBits.setValue(field_5_options, -1);
@ -147,8 +137,8 @@ public final class CFRuleRecord extends Record
this(conditionType, comparisonOperation); this(conditionType, comparisonOperation);
field_1_condition_type = CONDITION_TYPE_CELL_VALUE_IS; field_1_condition_type = CONDITION_TYPE_CELL_VALUE_IS;
field_2_comparison_operator = comparisonOperation; field_2_comparison_operator = comparisonOperation;
setParsedExpression1(formula1); field_17_formula1 = formula1;
setParsedExpression2(formula2); field_18_formula2 = formula2;
} }
/** /**
@ -167,63 +157,38 @@ public final class CFRuleRecord extends Record
Ptg[] formula1 = parseFormula(formulaText1, workbook); Ptg[] formula1 = parseFormula(formulaText1, workbook);
Ptg[] formula2 = parseFormula(formulaText2, workbook); Ptg[] formula2 = parseFormula(formulaText2, workbook);
return new CFRuleRecord(CONDITION_TYPE_CELL_VALUE_IS, comparisonOperation, formula1, formula2); return new CFRuleRecord(CONDITION_TYPE_CELL_VALUE_IS, comparisonOperation, formula1, formula2);
} }
/** public CFRuleRecord(RecordInputStream in) {
* Constructs a Formula record and sets its fields appropriately.
* Note - id must be 0x06 (NOT 0x406 see MSKB #Q184647 for an
* "explanation of this bug in the documentation) or an exception
* will be throw upon validation
*
* @param in the RecordInputstream to read the record from
*/
public CFRuleRecord(RecordInputStream in)
{
super(in); super(in);
} }
protected void fillFields(RecordInputStream in) { protected void fillFields(RecordInputStream in) {
try { field_1_condition_type = in.readByte();
field_1_condition_type = in.readByte(); field_2_comparison_operator = in.readByte();
field_2_comparison_operator = in.readByte(); int field_3_formula1_len = in.readUShort();
field_3_formula1_len = in.readShort(); int field_4_formula2_len = in.readUShort();
field_4_formula2_len = in.readShort(); field_5_options = in.readInt();
field_5_options = in.readInt(); field_6_not_used = in.readShort();
field_6_not_used = in.readShort();
if (containsFontFormattingBlock()) { if (containsFontFormattingBlock()) {
fontFormatting = new FontFormatting(in); fontFormatting = new FontFormatting(in);
}
if (containsBorderFormattingBlock()) {
borderFormatting = new BorderFormatting(in);
}
if (containsPatternFormattingBlock()) {
patternFormatting = new PatternFormatting(in);
}
if (field_3_formula1_len > 0) {
Stack ptgs = Ptg.createParsedExpressionTokens(field_3_formula1_len, in);
// Now convert any fields as required
ptgs = SharedFormulaRecord.convertSharedFormulas(ptgs, 0, 0);
field_17_formula1 = toArray(ptgs);
}
if (field_4_formula2_len > 0) {
Stack ptgs = Ptg.createParsedExpressionTokens(field_4_formula2_len, in);
// Now convert any fields as required
ptgs = SharedFormulaRecord.convertSharedFormulas(ptgs, 0, 0);
field_18_formula2 = toArray(ptgs);
}
} catch (java.lang.UnsupportedOperationException uoe) {
throw new RecordFormatException(uoe);
} }
if (containsBorderFormattingBlock()) {
borderFormatting = new BorderFormatting(in);
}
if (containsPatternFormattingBlock()) {
patternFormatting = new PatternFormatting(in);
}
if (field_3_formula1_len > 0) {
field_17_formula1 = Ptg.readTokens(field_3_formula1_len, in);
}
if (field_4_formula2_len > 0) {
field_18_formula2 = Ptg.readTokens(field_4_formula2_len, in);
}
} }
public byte getConditionType() public byte getConditionType()
@ -323,24 +288,6 @@ public final class CFRuleRecord extends Record
} }
/**
* get the length (in number of tokens) of the expression 1
* @return expression length
*/
private short getExpression1Length()
{
return field_3_formula1_len;
}
/**
* get the length (in number of tokens) of the expression 2
* @return expression length
*/
private short getExpression2Length()
{
return field_4_formula2_len;
}
/** /**
* get the option flags * get the option flags
* *
@ -489,16 +436,6 @@ public final class CFRuleRecord extends Record
return field_18_formula2; return field_18_formula2;
} }
private void setParsedExpression1(Ptg[] ptgs) {
short len = getTotalPtgSize(field_17_formula1 = ptgs);
field_3_formula1_len = len;
}
private void setParsedExpression2(Ptg[] ptgs) {
short len = getTotalPtgSize(field_18_formula2 = ptgs);
field_4_formula2_len = len;
}
/** /**
* called by constructor, should throw runtime exception in the event of a * called by constructor, should throw runtime exception in the event of a
* record passed with a differing ID. * record passed with a differing ID.
@ -519,6 +456,17 @@ public final class CFRuleRecord extends Record
return sid; return sid;
} }
/**
* @param ptgs may be <code>null</code>
* @return encoded size of the formula
*/
private static int getFormulaSize(Ptg[] ptgs) {
if (ptgs == null) {
return 0;
}
return Ptg.getEncodedSize(ptgs);
}
/** /**
* called by the class that is responsible for writing this sucker. * called by the class that is responsible for writing this sucker.
* Subclasses should implement this so that their data is passed back in a * Subclasses should implement this so that their data is passed back in a
@ -528,18 +476,20 @@ public final class CFRuleRecord extends Record
* @param data byte array containing instance data * @param data byte array containing instance data
* @return number of bytes written * @return number of bytes written
*/ */
public int serialize(int pOffset, byte [] data) public int serialize(int pOffset, byte [] data)
{ {
int formula1Len=getFormulaSize(field_17_formula1);
int formula2Len=getFormulaSize(field_18_formula2);
int offset = pOffset; int offset = pOffset;
int recordsize = getRecordSize(); int recordsize = getRecordSize();
LittleEndian.putShort(data, 0 + offset, sid); LittleEndian.putShort(data, 0 + offset, sid);
LittleEndian.putShort(data, 2 + offset, (short)(recordsize-4)); LittleEndian.putShort(data, 2 + offset, (short)(recordsize-4));
data[4 + offset] = field_1_condition_type; data[4 + offset] = field_1_condition_type;
data[5 + offset] = field_2_comparison_operator; data[5 + offset] = field_2_comparison_operator;
LittleEndian.putShort(data, 6 + offset, field_3_formula1_len); LittleEndian.putUShort(data, 6 + offset, formula1Len);
LittleEndian.putShort(data, 8 + offset, field_4_formula2_len); LittleEndian.putUShort(data, 8 + offset, formula2Len);
LittleEndian.putInt(data, 10 + offset, field_5_options); LittleEndian.putInt(data, 10 + offset, field_5_options);
LittleEndian.putShort(data,14 + offset, field_6_not_used); LittleEndian.putShort(data,14 + offset, field_6_not_used);
@ -562,16 +512,12 @@ public final class CFRuleRecord extends Record
offset += patternFormatting.serialize(offset, data); offset += patternFormatting.serialize(offset, data);
} }
if (getExpression1Length()>0) if (field_17_formula1 != null) {
{ offset += Ptg.serializePtgs(field_17_formula1, data, offset);
Ptg.serializePtgStack(convertToTokenStack(field_17_formula1), data, offset);
offset += getExpression1Length();
} }
if (getExpression2Length()>0) if (field_18_formula2 != null) {
{ offset += Ptg.serializePtgs(field_18_formula2, data, offset);
Ptg.serializePtgStack(convertToTokenStack(field_18_formula2), data, offset);
offset += getExpression2Length();
} }
if(offset - pOffset != recordsize) { if(offset - pOffset != recordsize) {
throw new IllegalStateException("write mismatch (" + (offset - pOffset) + "!=" + recordsize + ")"); throw new IllegalStateException("write mismatch (" + (offset - pOffset) + "!=" + recordsize + ")");
@ -586,24 +532,12 @@ public final class CFRuleRecord extends Record
(containsFontFormattingBlock()?fontFormatting.getRawRecord().length:0)+ (containsFontFormattingBlock()?fontFormatting.getRawRecord().length:0)+
(containsBorderFormattingBlock()?8:0)+ (containsBorderFormattingBlock()?8:0)+
(containsPatternFormattingBlock()?4:0)+ (containsPatternFormattingBlock()?4:0)+
getExpression1Length()+ getFormulaSize(field_17_formula1)+
getExpression2Length() getFormulaSize(field_18_formula2)
; ;
return retval; return retval;
} }
private short getTotalPtgSize(Ptg[] ptgs)
{
if( ptgs == null) {
return 0;
}
short retval = 0;
for (int i = 0; i < ptgs.length; i++)
{
retval += ptgs[i].getSize();
}
return retval;
}
public String toString() public String toString()
{ {
@ -629,8 +563,6 @@ public final class CFRuleRecord extends Record
public Object clone() { public Object clone() {
CFRuleRecord rec = new CFRuleRecord(field_1_condition_type, field_2_comparison_operator); CFRuleRecord rec = new CFRuleRecord(field_1_condition_type, field_2_comparison_operator);
rec.field_3_formula1_len = field_3_formula1_len;
rec.field_4_formula2_len = field_4_formula2_len;
rec.field_5_options = field_5_options; rec.field_5_options = field_5_options;
rec.field_6_not_used = field_6_not_used; rec.field_6_not_used = field_6_not_used;
if (containsFontFormattingBlock()) { if (containsFontFormattingBlock()) {
@ -642,10 +574,10 @@ public final class CFRuleRecord extends Record
if (containsPatternFormattingBlock()) { if (containsPatternFormattingBlock()) {
rec.patternFormatting = (PatternFormatting) patternFormatting.clone(); rec.patternFormatting = (PatternFormatting) patternFormatting.clone();
} }
if (field_3_formula1_len > 0) { if (field_17_formula1 != null) {
rec.field_17_formula1 = (Ptg[]) field_17_formula1.clone(); rec.field_17_formula1 = (Ptg[]) field_17_formula1.clone();
} }
if (field_4_formula2_len > 0) { if (field_18_formula2 != null) {
rec.field_18_formula2 = (Ptg[]) field_18_formula2.clone(); rec.field_18_formula2 = (Ptg[]) field_18_formula2.clone();
} }
@ -653,30 +585,17 @@ public final class CFRuleRecord extends Record
} }
/** /**
* TODO - parse conditional format formulas properly i.e. produce tRefN and tAreaN instead of tRef and tArea
* this call will produce the wrong results if the formula contains any cell references
* One approach might be to apply the inverse of SharedFormulaRecord.convertSharedFormulas(Stack, int, int)
* Note - two extra parameters (rowIx & colIx) will be required. They probably come from one of the Region objects.
*
* @return <code>null</code> if <tt>formula</tt> was null. * @return <code>null</code> if <tt>formula</tt> was null.
*/ */
private static Ptg[] parseFormula(String formula, HSSFWorkbook workbook) private static Ptg[] parseFormula(String formula, HSSFWorkbook workbook) {
{
if(formula == null) { if(formula == null) {
return null; return null;
} }
return FormulaParser.parse(formula, workbook); return FormulaParser.parse(formula, workbook);
} }
// TODO - treat formulas as token arrays instead of Stacks throughout the rest of POI
private static Stack convertToTokenStack(Ptg[] ptgs)
{
Stack parsedExpression = new Stack();
// fill the Ptg Stack with Ptgs of new formula
for (int k = 0; k < ptgs.length; k++)
{
parsedExpression.push(ptgs[ k ]);
}
return parsedExpression;
}
private static Ptg[] toArray(Stack ptgs) {
Ptg[] result = new Ptg[ptgs.size()];
ptgs.toArray(result);
return result;
}
} }

View File

@ -14,7 +14,6 @@
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.record; package org.apache.poi.hssf.record;
@ -22,9 +21,8 @@ import java.util.Iterator;
import java.util.List; import java.util.List;
import java.util.Stack; import java.util.Stack;
import org.apache.poi.hssf.model.FormulaParser;
import org.apache.poi.hssf.record.formula.Area3DPtg; import org.apache.poi.hssf.record.formula.Area3DPtg;
import org.apache.poi.hssf.record.formula.DeletedArea3DPtg;
import org.apache.poi.hssf.record.formula.DeletedRef3DPtg;
import org.apache.poi.hssf.record.formula.Ptg; import org.apache.poi.hssf.record.formula.Ptg;
import org.apache.poi.hssf.record.formula.Ref3DPtg; import org.apache.poi.hssf.record.formula.Ref3DPtg;
import org.apache.poi.hssf.record.formula.UnionPtg; import org.apache.poi.hssf.record.formula.UnionPtg;
@ -44,8 +42,7 @@ import org.apache.poi.util.StringUtil;
* @author Glen Stampoultzis (glens at apache.org) * @author Glen Stampoultzis (glens at apache.org)
* @version 1.0-pre * @version 1.0-pre
*/ */
public final class NameRecord extends Record {
public class NameRecord extends Record {
/** /**
*/ */
public final static short sid = 0x18; //Docs says that it is 0x218 public final static short sid = 0x18; //Docs says that it is 0x218
@ -650,50 +647,9 @@ public class NameRecord extends Record {
/** gets the reference , the area only (range) /** gets the reference , the area only (range)
* @return area reference * @return area reference
*/ */
public String getAreaReference(HSSFWorkbook book){ public String getAreaReference(HSSFWorkbook book){
if (field_13_name_definition == null || field_13_name_definition.isEmpty()) return "Error"; return FormulaParser.toFormulaString(book, field_13_name_definition);
Ptg ptg = (Ptg) field_13_name_definition.peek(); }
String result = "";
// If it's a union, descend in and process
if (ptg.getClass() == UnionPtg.class) {
Iterator it =field_13_name_definition.iterator();
while( it.hasNext() ) {
Ptg p = (Ptg)it.next();
String thisRes = getAreaRefString(p, book);
if(thisRes.length() > 0) {
// Add a comma to the end if needed
if(result.length() > 0 && !result.endsWith(",")) {
result += ",";
}
// And add the string it corresponds to
result += thisRes;
}
}
} else {
// Otherwise just get the string
result = getAreaRefString(ptg, book);
}
return result;
}
/**
* Turn the given ptg into a string, or
* return an empty string if nothing is possible
* for it.
*/
private String getAreaRefString(Ptg ptg,HSSFWorkbook book) {
if (ptg.getClass() == Area3DPtg.class){
return ptg.toFormulaString(book);
} else if (ptg.getClass() == Ref3DPtg.class){
return ptg.toFormulaString(book);
} else if (ptg.getClass() == DeletedArea3DPtg.class || ptg.getClass() == DeletedRef3DPtg.class) {
return "#REF!";
}
return "";
}
/** sets the reference , the area only (range) /** sets the reference , the area only (range)
* @param ref area reference * @param ref area reference

View File

@ -35,7 +35,7 @@ import org.apache.poi.util.LittleEndian;
* @author Jason Height (jheight at chariot dot net dot au) * @author Jason Height (jheight at chariot dot net dot au)
* @version 1.0-pre * @version 1.0-pre
*/ */
public class Area3DPtg extends OperandPtg implements AreaI { public final class Area3DPtg extends OperandPtg implements AreaI {
public final static byte sid = 0x3b; public final static byte sid = 0x3b;
private final static int SIZE = 11; // 10 + 1 for Ptg private final static int SIZE = 11; // 10 + 1 for Ptg
private short field_1_index_extern_sheet; private short field_1_index_extern_sheet;

View File

@ -18,6 +18,9 @@
package org.apache.poi.hssf.record.formula; package org.apache.poi.hssf.record.formula;
import org.apache.poi.hssf.record.RecordInputStream; import org.apache.poi.hssf.record.RecordInputStream;
import org.apache.poi.ss.usermodel.ErrorConstants;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.util.LittleEndian;
/** /**
* Title: Deleted Area 3D Ptg - 3D referecnce (Sheet + Area)<P> * Title: Deleted Area 3D Ptg - 3D referecnce (Sheet + Area)<P>
@ -26,19 +29,30 @@ import org.apache.poi.hssf.record.RecordInputStream;
* @author Patrick Luby * @author Patrick Luby
* @version 1.0-pre * @version 1.0-pre
*/ */
public final class DeletedArea3DPtg extends OperandPtg {
public class DeletedArea3DPtg extends Area3DPtg
{
public final static byte sid = 0x3d; public final static byte sid = 0x3d;
private final int field_1_index_extern_sheet;
private final int unused1;
private final int unused2;
/** Creates new DeletedArea3DPtg */ public DeletedArea3DPtg( RecordInputStream in) {
public DeletedArea3DPtg( String arearef, short externIdx ) field_1_index_extern_sheet = in.readUShort();
{ unused1 = in.readInt();
super(arearef, externIdx); unused2 = in.readInt();
} }
public String toFormulaString(Workbook book) {
public DeletedArea3DPtg( RecordInputStream in) return ErrorConstants.getText(ErrorConstants.ERROR_REF);
{ }
super(in); public byte getDefaultOperandClass() {
} return Ptg.CLASS_REF;
}
public int getSize() {
return 11;
}
public void writeBytes(byte[] data, int offset) {
LittleEndian.putByte(data, 0 + offset, sid + getPtgClass());
LittleEndian.putUShort(data, 1 + offset, field_1_index_extern_sheet);
LittleEndian.putInt(data, 3 + offset, unused1);
LittleEndian.putInt(data, 7 + offset, unused2);
}
} }

View File

@ -15,11 +15,13 @@
limitations under the License. limitations under the License.
==================================================================== */ ==================================================================== */
package org.apache.poi.hssf.record.formula; package org.apache.poi.hssf.record.formula;
import org.apache.poi.hssf.record.RecordInputStream; import org.apache.poi.hssf.record.RecordInputStream;
import org.apache.poi.ss.usermodel.ErrorConstants;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.util.LittleEndian;
/** /**
* Title: Deleted Reference 3D Ptg <P> * Title: Deleted Reference 3D Ptg <P>
@ -28,16 +30,29 @@ import org.apache.poi.hssf.record.RecordInputStream;
* @author Patrick Luby * @author Patrick Luby
* @version 1.0-pre * @version 1.0-pre
*/ */
public final class DeletedRef3DPtg extends OperandPtg {
public final static byte sid = 0x3c;
private final int field_1_index_extern_sheet;
private final int unused1;
public class DeletedRef3DPtg extends Ref3DPtg { /** Creates new DeletedRef3DPtg */
public final static byte sid = 0x3c; public DeletedRef3DPtg(RecordInputStream in) {
field_1_index_extern_sheet = in.readUShort();
unused1 = in.readInt();
}
/** Creates new DeletedRef3DPtg */ public String toFormulaString(Workbook book) {
public DeletedRef3DPtg(RecordInputStream in) { return ErrorConstants.getText(ErrorConstants.ERROR_REF);
super(in); }
} public byte getDefaultOperandClass() {
return Ptg.CLASS_REF;
public DeletedRef3DPtg(String cellref, short externIdx ) { }
super(cellref, externIdx); public int getSize() {
} return 7;
}
public void writeBytes(byte[] data, int offset) {
LittleEndian.putByte(data, 0 + offset, sid + getPtgClass());
LittleEndian.putUShort(data, 1 + offset, field_1_index_extern_sheet);
LittleEndian.putInt(data, 3 + offset, unused1);
}
} }

View File

@ -34,7 +34,7 @@ import org.apache.poi.util.LittleEndian;
* @author Jason Height (jheight at chariot dot net dot au) * @author Jason Height (jheight at chariot dot net dot au)
* @version 1.0-pre * @version 1.0-pre
*/ */
public class Ref3DPtg extends OperandPtg { public final class Ref3DPtg extends OperandPtg {
public final static byte sid = 0x3a; public final static byte sid = 0x3a;
private final static int SIZE = 7; // 6 + 1 for Ptg private final static int SIZE = 7; // 6 + 1 for Ptg
private short field_1_index_extern_sheet; private short field_1_index_extern_sheet;

View File

@ -16,67 +16,12 @@
==================================================================== */ ==================================================================== */
package org.apache.poi.hssf.usermodel; package org.apache.poi.hssf.usermodel;
import org.apache.poi.ss.usermodel.ErrorConstants;
/** /**
* Contains raw Excel error codes (as defined in OOO's excelfileformat.pdf (2.5.6) * Contains raw Excel error codes (as defined in OOO's excelfileformat.pdf (2.5.6)
* *
* @author Michael Harhen * @author Michael Harhen
*/ */
public final class HSSFErrorConstants { public final class HSSFErrorConstants extends ErrorConstants {
private HSSFErrorConstants() {
// no instances of this class
}
/** <b>#NULL!</b> - Intersection of two cell ranges is empty */
public static final int ERROR_NULL = 0x00;
/** <b>#DIV/0!</b> - Division by zero */
public static final int ERROR_DIV_0 = 0x07;
/** <b>#VALUE!</b> - Wrong type of operand */
public static final int ERROR_VALUE = 0x0F;
/** <b>#REF!</b> - Illegal or deleted cell reference */
public static final int ERROR_REF = 0x17;
/** <b>#NAME?</b> - Wrong function or range name */
public static final int ERROR_NAME = 0x1D;
/** <b>#NUM!</b> - Value range overflow */
public static final int ERROR_NUM = 0x24;
/** <b>#N/A</b> - Argument or function not available */
public static final int ERROR_NA = 0x2A;
/**
* @return Standard Excel error literal for the specified error code.
* @throws IllegalArgumentException if the specified error code is not one of the 7
* standard error codes
*/
public static final String getText(int errorCode) {
switch(errorCode) {
case ERROR_NULL: return "#NULL!";
case ERROR_DIV_0: return "#DIV/0!";
case ERROR_VALUE: return "#VALUE!";
case ERROR_REF: return "#REF!";
case ERROR_NAME: return "#NAME?";
case ERROR_NUM: return "#NUM!";
case ERROR_NA: return "#N/A";
}
throw new IllegalArgumentException("Bad error code (" + errorCode + ")");
}
/**
* @return <code>true</code> if the specified error code is a standard Excel error code.
*/
public static final boolean isValidCode(int errorCode) {
// This method exists because it would be bad to force clients to catch
// IllegalArgumentException if there were potential for passing an invalid error code.
switch(errorCode) {
case ERROR_NULL:
case ERROR_DIV_0:
case ERROR_VALUE:
case ERROR_REF:
case ERROR_NAME:
case ERROR_NUM:
case ERROR_NA:
return true;
}
return false;
}
} }

View File

@ -39,7 +39,8 @@ public final class HSSFSheetConditionalFormatting {
/** /**
* A factory method allowing to create a conditional formatting rule * A factory method allowing to create a conditional formatting rule
* with a cell comparison operator * with a cell comparison operator<p/>
* TODO - formulas containing cell references are currently not parsed properly
* *
* @param comparisonOperation - a constant value from * @param comparisonOperation - a constant value from
* <tt>{@link HSSFConditionalFormattingRule.ComparisonOperator}</tt>: <p> * <tt>{@link HSSFConditionalFormattingRule.ComparisonOperator}</tt>: <p>
@ -72,8 +73,8 @@ public final class HSSFSheetConditionalFormatting {
/** /**
* A factory method allowing to create a conditional formatting rule with a formula.<br> * A factory method allowing to create a conditional formatting rule with a formula.<br>
* *
* The formatting rules are applied by Excel when the value of the formula not equal to 0. * The formatting rules are applied by Excel when the value of the formula not equal to 0.<p/>
* * TODO - formulas containing cell references are currently not parsed properly
* @param formula - formula for the valued, compared with the cell * @param formula - formula for the valued, compared with the cell
*/ */
public HSSFConditionalFormattingRule createConditionalFormattingRule(String formula) { public HSSFConditionalFormattingRule createConditionalFormattingRule(String formula) {

View File

@ -0,0 +1,82 @@
/* ====================================================================
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.ss.usermodel;
/**
* Contains raw Excel error codes (as defined in OOO's excelfileformat.pdf (2.5.6)
*
* @author Michael Harhen
*/
public class ErrorConstants {
protected ErrorConstants() {
// no instances of this class
}
/** <b>#NULL!</b> - Intersection of two cell ranges is empty */
public static final int ERROR_NULL = 0x00;
/** <b>#DIV/0!</b> - Division by zero */
public static final int ERROR_DIV_0 = 0x07;
/** <b>#VALUE!</b> - Wrong type of operand */
public static final int ERROR_VALUE = 0x0F;
/** <b>#REF!</b> - Illegal or deleted cell reference */
public static final int ERROR_REF = 0x17;
/** <b>#NAME?</b> - Wrong function or range name */
public static final int ERROR_NAME = 0x1D;
/** <b>#NUM!</b> - Value range overflow */
public static final int ERROR_NUM = 0x24;
/** <b>#N/A</b> - Argument or function not available */
public static final int ERROR_NA = 0x2A;
/**
* @return Standard Excel error literal for the specified error code.
* @throws IllegalArgumentException if the specified error code is not one of the 7
* standard error codes
*/
public static final String getText(int errorCode) {
switch(errorCode) {
case ERROR_NULL: return "#NULL!";
case ERROR_DIV_0: return "#DIV/0!";
case ERROR_VALUE: return "#VALUE!";
case ERROR_REF: return "#REF!";
case ERROR_NAME: return "#NAME?";
case ERROR_NUM: return "#NUM!";
case ERROR_NA: return "#N/A";
}
throw new IllegalArgumentException("Bad error code (" + errorCode + ")");
}
/**
* @return <code>true</code> if the specified error code is a standard Excel error code.
*/
public static final boolean isValidCode(int errorCode) {
// This method exists because it would be bad to force clients to catch
// IllegalArgumentException if there were potential for passing an invalid error code.
switch(errorCode) {
case ERROR_NULL:
case ERROR_DIV_0:
case ERROR_VALUE:
case ERROR_REF:
case ERROR_NAME:
case ERROR_NUM:
case ERROR_NA:
return true;
}
return false;
}
}

View File

@ -355,7 +355,7 @@ public abstract class TextShape extends SimpleShape {
*/ */
public float getMarginLeft(){ public float getMarginLeft(){
EscherOptRecord opt = (EscherOptRecord)getEscherChild(_escherContainer, EscherOptRecord.RECORD_ID); EscherOptRecord opt = (EscherOptRecord)getEscherChild(_escherContainer, EscherOptRecord.RECORD_ID);
EscherSimpleProperty prop = (EscherSimpleProperty)getEscherProperty(opt, EscherProperties.TEXT__TEXTBOTTOM); EscherSimpleProperty prop = (EscherSimpleProperty)getEscherProperty(opt, EscherProperties.TEXT__TEXTLEFT);
int val = prop == null ? EMU_PER_INCH/10 : prop.getPropertyValue(); int val = prop == null ? EMU_PER_INCH/10 : prop.getPropertyValue();
return (float)val/EMU_PER_POINT; return (float)val/EMU_PER_POINT;
} }

View File

@ -635,27 +635,24 @@ public class Range
/** /**
* Replace (one instance of) a piece of text with another... * Replace (one instance of) a piece of text with another...
* *
* @param pPlaceHolder The text to be replaced (e.g., "${company}") * @param pPlaceHolder The text to be replaced (e.g., "${organization}")
* @param pValue The replacement text (e.g., "Cognocys, Inc.") * @param pValue The replacement text (e.g., "Apache Software Foundation")
* @param pDocument The <code>HWPFDocument</code> in which the placeholder was found * @param pOffset The offset or index where the text to be replaced begins
* @param pStartOffset The offset or index where the <code>CharacterRun</code> begins * (relative to/within this <code>Range</code>)
* @param pPlaceHolderIndex The offset or index of the placeholder,
* relative to the <code>CharacterRun</code> where
* <code>pPlaceHolder</code> was found
*/ */
protected void replaceText(String pPlaceHolder, String pValue, public void replaceText(String pPlaceHolder, String pValue, int pOffset)
int pStartOffset, int pPlaceHolderIndex, HWPFDocument pDocument) { {
int absPlaceHolderIndex = pStartOffset + pPlaceHolderIndex; int absPlaceHolderIndex = getStartOffset() + pOffset;
Range subRange = new Range( Range subRange = new Range(
absPlaceHolderIndex, absPlaceHolderIndex,
(absPlaceHolderIndex + pPlaceHolder.length()), pDocument (absPlaceHolderIndex + pPlaceHolder.length()), getDocument()
); );
if (subRange.usesUnicode()) { if (subRange.usesUnicode()) {
absPlaceHolderIndex = pStartOffset + (pPlaceHolderIndex * 2); absPlaceHolderIndex = getStartOffset() + (pOffset * 2);
subRange = new Range( subRange = new Range(
absPlaceHolderIndex, absPlaceHolderIndex,
(absPlaceHolderIndex + (pPlaceHolder.length() * 2)), (absPlaceHolderIndex + (pPlaceHolder.length() * 2)),
pDocument getDocument()
); );
} }
@ -665,13 +662,13 @@ public class Range
subRange = new Range( subRange = new Range(
(absPlaceHolderIndex + pValue.length()), (absPlaceHolderIndex + pValue.length()),
(absPlaceHolderIndex + pPlaceHolder.length() + pValue.length()), (absPlaceHolderIndex + pPlaceHolder.length() + pValue.length()),
pDocument getDocument()
); );
if (subRange.usesUnicode()) if (subRange.usesUnicode())
subRange = new Range( subRange = new Range(
(absPlaceHolderIndex + (pValue.length() * 2)), (absPlaceHolderIndex + (pValue.length() * 2)),
(absPlaceHolderIndex + (pPlaceHolder.length() * 2) + (absPlaceHolderIndex + (pPlaceHolder.length() * 2) +
(pValue.length() * 2)), pDocument (pValue.length() * 2)), getDocument()
); );
subRange.delete(); subRange.delete();
@ -942,4 +939,9 @@ public class Range
return _end; return _end;
} }
protected HWPFDocument getDocument() {
return _doc;
}
} }

View File

@ -23,6 +23,7 @@ import junit.framework.TestCase;
import java.io.*; import java.io.*;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashMap;
import org.apache.poi.hslf.usermodel.SlideShow; import org.apache.poi.hslf.usermodel.SlideShow;
import org.apache.poi.hslf.record.TextHeaderAtom; import org.apache.poi.hslf.record.TextHeaderAtom;
@ -157,4 +158,46 @@ public class TestTextShape extends TestCase {
assertEquals("Testing TextShape", shape1.getTextRun().getText()); assertEquals("Testing TextShape", shape1.getTextRun().getText());
} }
public void testMargins() throws IOException {
FileInputStream is = new FileInputStream(new File(cwd, "text-margins.ppt"));
SlideShow ppt = new SlideShow(is);
is.close();
Slide slide = ppt.getSlides()[0];
HashMap map = new HashMap();
Shape[] shape = slide.getShapes();
for (int i = 0; i < shape.length; i++) {
if(shape[i] instanceof TextShape){
TextShape tx = (TextShape)shape[i];
map.put(tx.getText(), tx);
}
}
TextShape tx;
tx = (TextShape)map.get("TEST1");
assertEquals(0.1, tx.getMarginLeft()*Shape.EMU_PER_POINT/Shape.EMU_PER_INCH, 0.01);
assertEquals(0.1, tx.getMarginRight()*Shape.EMU_PER_POINT/Shape.EMU_PER_INCH, 0.01);
assertEquals(0.39, tx.getMarginTop()*Shape.EMU_PER_POINT/Shape.EMU_PER_INCH, 0.01);
assertEquals(0.05, tx.getMarginBottom()*Shape.EMU_PER_POINT/Shape.EMU_PER_INCH, 0.01);
tx = (TextShape)map.get("TEST2");
assertEquals(0.1, tx.getMarginLeft()*Shape.EMU_PER_POINT/Shape.EMU_PER_INCH, 0.01);
assertEquals(0.1, tx.getMarginRight()*Shape.EMU_PER_POINT/Shape.EMU_PER_INCH, 0.01);
assertEquals(0.05, tx.getMarginTop()*Shape.EMU_PER_POINT/Shape.EMU_PER_INCH, 0.01);
assertEquals(0.39, tx.getMarginBottom()*Shape.EMU_PER_POINT/Shape.EMU_PER_INCH, 0.01);
tx = (TextShape)map.get("TEST3");
assertEquals(0.39, tx.getMarginLeft()*Shape.EMU_PER_POINT/Shape.EMU_PER_INCH, 0.01);
assertEquals(0.1, tx.getMarginRight()*Shape.EMU_PER_POINT/Shape.EMU_PER_INCH, 0.01);
assertEquals(0.05, tx.getMarginTop()*Shape.EMU_PER_POINT/Shape.EMU_PER_INCH, 0.01);
assertEquals(0.05, tx.getMarginBottom()*Shape.EMU_PER_POINT/Shape.EMU_PER_INCH, 0.01);
tx = (TextShape)map.get("TEST4");
assertEquals(0.1, tx.getMarginLeft()*Shape.EMU_PER_POINT/Shape.EMU_PER_INCH, 0.01);
assertEquals(0.39, tx.getMarginRight()*Shape.EMU_PER_POINT/Shape.EMU_PER_INCH, 0.01);
assertEquals(0.05, tx.getMarginTop()*Shape.EMU_PER_POINT/Shape.EMU_PER_INCH, 0.01);
assertEquals(0.05, tx.getMarginBottom()*Shape.EMU_PER_POINT/Shape.EMU_PER_INCH, 0.01);
}
} }

View File

@ -0,0 +1,119 @@
/* ====================================================================
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.hwpf.usermodel;
import java.io.ByteArrayOutputStream;
import java.io.FileInputStream;
import java.util.List;
import org.apache.poi.hwpf.HWPFDocument;
import org.apache.poi.hwpf.model.PicturesTable;
import org.apache.poi.hwpf.usermodel.Picture;
import junit.framework.TestCase;
/**
* Test to see if Range.replaceText() works even if the Range contains a
* CharacterRun that uses Unicode characters.
*/
public class TestRangeReplacement extends TestCase {
// u201c and u201d are "smart-quotes"
private String originalText =
"It is used to confirm that text replacement works even if Unicode characters (such as \u201c\u2014\u201d (U+2014), \u201c\u2e8e\u201d (U+2E8E), or \u201c\u2714\u201d (U+2714)) are present. Everybody should be thankful to the ${organization} and all the POI contributors for their assistance in this matter.\r";
private String searchText = "${organization}";
private String replacementText = "Apache Software Foundation";
private String expectedText =
"It is used to confirm that text replacement works even if Unicode characters (such as \u201c\u2014\u201d (U+2014), \u201c\u2e8e\u201d (U+2E8E), or \u201c\u2714\u201d (U+2714)) are present. Everybody should be thankful to the Apache Software Foundation and all the POI contributors for their assistance in this matter.\r";
private String illustrativeDocFile;
protected void setUp() throws Exception {
String dirname = System.getProperty("HWPF.testdata.path");
illustrativeDocFile = dirname + "/testRangeReplacement.doc";
}
/**
* Test just opening the files
*/
public void testOpen() throws Exception {
HWPFDocument docA = new HWPFDocument(new FileInputStream(illustrativeDocFile));
}
/**
* Test (more "confirm" than test) that we have the general structure that we expect to have.
*/
public void testDocStructure() throws Exception {
HWPFDocument daDoc = new HWPFDocument(new FileInputStream(illustrativeDocFile));
Range range = daDoc.getRange();
assertEquals(1, range.numSections());
Section section = range.getSection(0);
assertEquals(5, section.numParagraphs());
Paragraph para = section.getParagraph(2);
assertEquals(5, para.numCharacterRuns());
String text = para.getCharacterRun(0).text() + para.getCharacterRun(1).text() +
para.getCharacterRun(2).text() + para.getCharacterRun(3).text() + para.getCharacterRun(4).text();
assertEquals(originalText, text);
}
/**
* Test that we can replace text in our Range with Unicode text.
*/
public void testRangeReplacement() throws Exception {
HWPFDocument daDoc = new HWPFDocument(new FileInputStream(illustrativeDocFile));
Range range = daDoc.getRange();
assertEquals(1, range.numSections());
Section section = range.getSection(0);
assertEquals(5, section.numParagraphs());
Paragraph para = section.getParagraph(2);
String text = para.text();
assertEquals(originalText, text);
int offset = text.indexOf(searchText);
assertEquals(181, offset);
para.replaceText(searchText, replacementText, offset);
// we need to let the model re-calculate the Range before we evaluate it
range = daDoc.getRange();
assertEquals(1, range.numSections());
section = range.getSection(0);
assertEquals(5, section.numParagraphs());
para = section.getParagraph(2);
text = para.text();
assertEquals(expectedText, text);
}
}

Binary file not shown.

View File

@ -17,12 +17,16 @@
package org.apache.poi.hssf.record; package org.apache.poi.hssf.record;
import junit.framework.AssertionFailedError;
import junit.framework.TestCase; import junit.framework.TestCase;
import org.apache.poi.hssf.record.CFRuleRecord.ComparisonOperator; import org.apache.poi.hssf.record.CFRuleRecord.ComparisonOperator;
import org.apache.poi.hssf.record.cf.BorderFormatting; import org.apache.poi.hssf.record.cf.BorderFormatting;
import org.apache.poi.hssf.record.cf.FontFormatting; import org.apache.poi.hssf.record.cf.FontFormatting;
import org.apache.poi.hssf.record.cf.PatternFormatting; import org.apache.poi.hssf.record.cf.PatternFormatting;
import org.apache.poi.hssf.record.formula.Ptg;
import org.apache.poi.hssf.record.formula.RefNPtg;
import org.apache.poi.hssf.record.formula.RefPtg;
import org.apache.poi.hssf.usermodel.HSSFWorkbook; import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.hssf.util.HSSFColor; import org.apache.poi.hssf.util.HSSFColor;
import org.apache.poi.util.LittleEndian; import org.apache.poi.util.LittleEndian;
@ -296,7 +300,57 @@ public final class TestCFRuleRecord extends TestCase
// check all remaining flag bits (some are not well understood yet) // check all remaining flag bits (some are not well understood yet)
assertEquals(0x203FFFFF, flags); assertEquals(0x203FFFFF, flags);
} }
private static final byte[] DATA_REFN = {
// formula extracted from bugzilla 45234 att 22141
1, 3,
9, // formula 1 length
0, 0, 0, -1, -1, 63, 32, 2, -128, 0, 0, 0, 5,
// formula 1: "=B3=1" (formula is relative to B4)
76, -1, -1, 0, -64, // tRefN(B1)
30, 1, 0,
11,
};
/**
* tRefN and tAreaN tokens must be preserved when re-serializing conditional format formulas
*/
public void testReserializeRefNTokens() {
RecordInputStream is = new TestcaseRecordInputStream(CFRuleRecord.sid, DATA_REFN);
CFRuleRecord rr = new CFRuleRecord(is);
Ptg[] ptgs = rr.getParsedExpression1();
assertEquals(3, ptgs.length);
if (ptgs[0] instanceof RefPtg) {
throw new AssertionFailedError("Identified bug 45234");
}
assertEquals(RefNPtg.class, ptgs[0].getClass());
RefNPtg refNPtg = (RefNPtg) ptgs[0];
assertTrue(refNPtg.isColRelative());
assertTrue(refNPtg.isRowRelative());
byte[] data = rr.serialize();
if (!compareArrays(DATA_REFN, 0, data, 4, DATA_REFN.length)) {
fail("Did not re-serialize correctly");
}
}
private static boolean compareArrays(byte[] arrayA, int offsetA, byte[] arrayB, int offsetB, int length) {
if (offsetA + length > arrayA.length) {
return false;
}
if (offsetB + length > arrayB.length) {
return false;
}
for (int i = 0; i < length; i++) {
if (arrayA[i+offsetA] != arrayB[i+offsetB]) {
return false;
}
}
return true;
}
public static void main(String[] ignored_args) public static void main(String[] ignored_args)
{ {

View File

@ -30,7 +30,10 @@ import junit.framework.TestCase;
import org.apache.poi.ss.util.Region; import org.apache.poi.ss.util.Region;
import org.apache.poi.hssf.HSSFTestDataSamples; import org.apache.poi.hssf.HSSFTestDataSamples;
import org.apache.poi.hssf.model.Workbook;
import org.apache.poi.hssf.record.EmbeddedObjectRefSubRecord; import org.apache.poi.hssf.record.EmbeddedObjectRefSubRecord;
import org.apache.poi.hssf.record.NameRecord;
import org.apache.poi.hssf.record.formula.DeletedArea3DPtg;
import org.apache.poi.util.TempFile; import org.apache.poi.util.TempFile;
/** /**
@ -990,4 +993,63 @@ public final class TestBugs extends TestCase {
fail(); fail();
} catch(FileNotFoundException e) {} } catch(FileNotFoundException e) {}
} }
/**
* Test that we can delete sheets without
* breaking the build in named ranges
* used for printing stuff.
* Currently broken, as we change the Ptg
*/
public void test30978() throws Exception {
HSSFWorkbook wb = openSample("30978-alt.xls");
assertEquals(1, wb.getNumberOfNames());
assertEquals(3, wb.getNumberOfSheets());
// Check all names fit within range, and use
// DeletedArea3DPtg
Workbook w = wb.getWorkbook();
for(int i=0; i<w.getNumNames(); i++) {
NameRecord r = w.getNameRecord(i);
assertTrue(r.getIndexToSheet() <= wb.getNumberOfSheets());
List nd = r.getNameDefinition();
assertEquals(1, nd.size());
assertTrue(nd.get(0) instanceof DeletedArea3DPtg);
}
// Delete the 2nd sheet
wb.removeSheetAt(1);
// Re-check
assertEquals(1, wb.getNumberOfNames());
assertEquals(2, wb.getNumberOfSheets());
for(int i=0; i<w.getNumNames(); i++) {
NameRecord r = w.getNameRecord(i);
assertTrue(r.getIndexToSheet() <= wb.getNumberOfSheets());
List nd = r.getNameDefinition();
assertEquals(1, nd.size());
assertTrue(nd.get(0) instanceof DeletedArea3DPtg);
}
// Save and re-load
wb = writeOutAndReadBack(wb);
w = wb.getWorkbook();
assertEquals(1, wb.getNumberOfNames());
assertEquals(2, wb.getNumberOfSheets());
for(int i=0; i<w.getNumNames(); i++) {
NameRecord r = w.getNameRecord(i);
assertTrue(r.getIndexToSheet() <= wb.getNumberOfSheets());
List nd = r.getNameDefinition();
assertEquals(1, nd.size());
assertTrue(nd.get(0) instanceof DeletedArea3DPtg);
}
}
} }