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
tags/REL_3_5_BETA2
@@ -10,14 +10,6 @@ Common Public License Version 1.0: | |||
http://www.opensource.org/licenses/cpl.php | |||
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, | |||
with their own licensing: |
@@ -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 Excel files, irrespective of if they are .xls or .xlsx</action> | |||
</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="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> |
@@ -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 Excel files, irrespective of if they are .xls or .xlsx</action> | |||
</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="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> |
@@ -604,8 +604,28 @@ public class Workbook implements Model | |||
fixTabIdRecord(); | |||
} | |||
// If we decide that we need to fix up | |||
// NameRecords, do it here | |||
// Within NameRecords, it's ok to have the formula | |||
// 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 | |||
)); | |||
} | |||
} | |||
} | |||
/** |
@@ -14,14 +14,10 @@ | |||
See the License for the specific language governing permissions and | |||
limitations under the License. | |||
==================================================================== */ | |||
package org.apache.poi.hssf.record; | |||
import java.util.Stack; | |||
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.FontFormatting; | |||
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.BitFieldFactory; | |||
import org.apache.poi.util.LittleEndian; | |||
import org.apache.poi.util.StringUtil; | |||
/** | |||
* Conditional Formatting Rule Record. | |||
@@ -59,9 +54,6 @@ public final class CFRuleRecord extends Record | |||
private byte field_2_comparison_operator; | |||
private short field_3_formula1_len; | |||
private short field_4_formula2_len; | |||
private int field_5_options; | |||
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_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 | |||
field_5_options = modificationBits.setValue(field_5_options, -1); | |||
@@ -147,8 +137,8 @@ public final class CFRuleRecord extends Record | |||
this(conditionType, comparisonOperation); | |||
field_1_condition_type = CONDITION_TYPE_CELL_VALUE_IS; | |||
field_2_comparison_operator = comparisonOperation; | |||
setParsedExpression1(formula1); | |||
setParsedExpression2(formula2); | |||
field_17_formula1 = formula1; | |||
field_18_formula2 = formula2; | |||
} | |||
/** | |||
@@ -167,63 +157,38 @@ public final class CFRuleRecord extends Record | |||
Ptg[] formula1 = parseFormula(formulaText1, workbook); | |||
Ptg[] formula2 = parseFormula(formulaText2, workbook); | |||
return new CFRuleRecord(CONDITION_TYPE_CELL_VALUE_IS, comparisonOperation, formula1, formula2); | |||
} | |||
/** | |||
* 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) | |||
{ | |||
public CFRuleRecord(RecordInputStream in) { | |||
super(in); | |||
} | |||
protected void fillFields(RecordInputStream in) { | |||
field_1_condition_type = in.readByte(); | |||
field_2_comparison_operator = in.readByte(); | |||
int field_3_formula1_len = in.readUShort(); | |||
int field_4_formula2_len = in.readUShort(); | |||
field_5_options = in.readInt(); | |||
field_6_not_used = in.readShort(); | |||
if (containsFontFormattingBlock()) { | |||
fontFormatting = new FontFormatting(in); | |||
} | |||
protected void fillFields(RecordInputStream in) { | |||
try { | |||
field_1_condition_type = in.readByte(); | |||
field_2_comparison_operator = in.readByte(); | |||
field_3_formula1_len = in.readShort(); | |||
field_4_formula2_len = in.readShort(); | |||
field_5_options = in.readInt(); | |||
field_6_not_used = in.readShort(); | |||
if (containsFontFormattingBlock()) { | |||
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() | |||
@@ -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 | |||
* | |||
@@ -489,16 +436,6 @@ public final class CFRuleRecord extends Record | |||
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 | |||
* record passed with a differing ID. | |||
@@ -519,6 +456,17 @@ public final class CFRuleRecord extends Record | |||
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. | |||
* 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 | |||
* @return number of bytes written | |||
*/ | |||
public int serialize(int pOffset, byte [] data) | |||
{ | |||
int formula1Len=getFormulaSize(field_17_formula1); | |||
int formula2Len=getFormulaSize(field_18_formula2); | |||
int offset = pOffset; | |||
int recordsize = getRecordSize(); | |||
LittleEndian.putShort(data, 0 + offset, sid); | |||
LittleEndian.putShort(data, 2 + offset, (short)(recordsize-4)); | |||
data[4 + offset] = field_1_condition_type; | |||
data[5 + offset] = field_2_comparison_operator; | |||
LittleEndian.putShort(data, 6 + offset, field_3_formula1_len); | |||
LittleEndian.putShort(data, 8 + offset, field_4_formula2_len); | |||
LittleEndian.putUShort(data, 6 + offset, formula1Len); | |||
LittleEndian.putUShort(data, 8 + offset, formula2Len); | |||
LittleEndian.putInt(data, 10 + offset, field_5_options); | |||
LittleEndian.putShort(data,14 + offset, field_6_not_used); | |||
@@ -562,16 +512,12 @@ public final class CFRuleRecord extends Record | |||
offset += patternFormatting.serialize(offset, data); | |||
} | |||
if (getExpression1Length()>0) | |||
{ | |||
Ptg.serializePtgStack(convertToTokenStack(field_17_formula1), data, offset); | |||
offset += getExpression1Length(); | |||
if (field_17_formula1 != null) { | |||
offset += Ptg.serializePtgs(field_17_formula1, data, offset); | |||
} | |||
if (getExpression2Length()>0) | |||
{ | |||
Ptg.serializePtgStack(convertToTokenStack(field_18_formula2), data, offset); | |||
offset += getExpression2Length(); | |||
if (field_18_formula2 != null) { | |||
offset += Ptg.serializePtgs(field_18_formula2, data, offset); | |||
} | |||
if(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)+ | |||
(containsBorderFormattingBlock()?8:0)+ | |||
(containsPatternFormattingBlock()?4:0)+ | |||
getExpression1Length()+ | |||
getExpression2Length() | |||
getFormulaSize(field_17_formula1)+ | |||
getFormulaSize(field_18_formula2) | |||
; | |||
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() | |||
{ | |||
@@ -629,8 +563,6 @@ public final class CFRuleRecord extends Record | |||
public Object clone() { | |||
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_6_not_used = field_6_not_used; | |||
if (containsFontFormattingBlock()) { | |||
@@ -642,10 +574,10 @@ public final class CFRuleRecord extends Record | |||
if (containsPatternFormattingBlock()) { | |||
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(); | |||
} | |||
if (field_4_formula2_len > 0) { | |||
if (field_18_formula2 != null) { | |||
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. | |||
*/ | |||
private static Ptg[] parseFormula(String formula, HSSFWorkbook workbook) | |||
{ | |||
private static Ptg[] parseFormula(String formula, HSSFWorkbook workbook) { | |||
if(formula == null) { | |||
return null; | |||
} | |||
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; | |||
} | |||
} |
@@ -14,7 +14,6 @@ | |||
See the License for the specific language governing permissions and | |||
limitations under the License. | |||
==================================================================== */ | |||
package org.apache.poi.hssf.record; | |||
@@ -22,9 +21,8 @@ import java.util.Iterator; | |||
import java.util.List; | |||
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.DeletedArea3DPtg; | |||
import org.apache.poi.hssf.record.formula.DeletedRef3DPtg; | |||
import org.apache.poi.hssf.record.formula.Ptg; | |||
import org.apache.poi.hssf.record.formula.Ref3DPtg; | |||
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) | |||
* @version 1.0-pre | |||
*/ | |||
public class NameRecord extends Record { | |||
public final class NameRecord extends Record { | |||
/** | |||
*/ | |||
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) | |||
* @return area reference | |||
*/ | |||
public String getAreaReference(HSSFWorkbook book){ | |||
if (field_13_name_definition == null || field_13_name_definition.isEmpty()) return "Error"; | |||
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 ""; | |||
} | |||
public String getAreaReference(HSSFWorkbook book){ | |||
return FormulaParser.toFormulaString(book, field_13_name_definition); | |||
} | |||
/** sets the reference , the area only (range) | |||
* @param ref area reference |
@@ -35,7 +35,7 @@ import org.apache.poi.util.LittleEndian; | |||
* @author Jason Height (jheight at chariot dot net dot au) | |||
* @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; | |||
private final static int SIZE = 11; // 10 + 1 for Ptg | |||
private short field_1_index_extern_sheet; |
@@ -18,6 +18,9 @@ | |||
package org.apache.poi.hssf.record.formula; | |||
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> | |||
@@ -26,19 +29,30 @@ import org.apache.poi.hssf.record.RecordInputStream; | |||
* @author Patrick Luby | |||
* @version 1.0-pre | |||
*/ | |||
public class DeletedArea3DPtg extends Area3DPtg | |||
{ | |||
public final class DeletedArea3DPtg extends OperandPtg { | |||
public final static byte sid = 0x3d; | |||
/** Creates new DeletedArea3DPtg */ | |||
public DeletedArea3DPtg( String arearef, short externIdx ) | |||
{ | |||
super(arearef, externIdx); | |||
} | |||
public DeletedArea3DPtg( RecordInputStream in) | |||
{ | |||
super(in); | |||
} | |||
private final int field_1_index_extern_sheet; | |||
private final int unused1; | |||
private final int unused2; | |||
public DeletedArea3DPtg( RecordInputStream in) { | |||
field_1_index_extern_sheet = in.readUShort(); | |||
unused1 = in.readInt(); | |||
unused2 = in.readInt(); | |||
} | |||
public String toFormulaString(Workbook book) { | |||
return ErrorConstants.getText(ErrorConstants.ERROR_REF); | |||
} | |||
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); | |||
} | |||
} |
@@ -15,11 +15,13 @@ | |||
limitations under the License. | |||
==================================================================== */ | |||
package org.apache.poi.hssf.record.formula; | |||
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> | |||
@@ -28,16 +30,29 @@ import org.apache.poi.hssf.record.RecordInputStream; | |||
* @author Patrick Luby | |||
* @version 1.0-pre | |||
*/ | |||
public class DeletedRef3DPtg extends Ref3DPtg { | |||
public final static byte sid = 0x3c; | |||
/** Creates new DeletedRef3DPtg */ | |||
public DeletedRef3DPtg(RecordInputStream in) { | |||
super(in); | |||
} | |||
public DeletedRef3DPtg(String cellref, short externIdx ) { | |||
super(cellref, externIdx); | |||
} | |||
public final class DeletedRef3DPtg extends OperandPtg { | |||
public final static byte sid = 0x3c; | |||
private final int field_1_index_extern_sheet; | |||
private final int unused1; | |||
/** Creates new DeletedRef3DPtg */ | |||
public DeletedRef3DPtg(RecordInputStream in) { | |||
field_1_index_extern_sheet = in.readUShort(); | |||
unused1 = in.readInt(); | |||
} | |||
public String toFormulaString(Workbook book) { | |||
return ErrorConstants.getText(ErrorConstants.ERROR_REF); | |||
} | |||
public byte getDefaultOperandClass() { | |||
return Ptg.CLASS_REF; | |||
} | |||
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); | |||
} | |||
} |
@@ -34,7 +34,7 @@ import org.apache.poi.util.LittleEndian; | |||
* @author Jason Height (jheight at chariot dot net dot au) | |||
* @version 1.0-pre | |||
*/ | |||
public class Ref3DPtg extends OperandPtg { | |||
public final class Ref3DPtg extends OperandPtg { | |||
public final static byte sid = 0x3a; | |||
private final static int SIZE = 7; // 6 + 1 for Ptg | |||
private short field_1_index_extern_sheet; |
@@ -16,67 +16,12 @@ | |||
==================================================================== */ | |||
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) | |||
* | |||
* @author Michael Harhen | |||
*/ | |||
public final class HSSFErrorConstants { | |||
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; | |||
} | |||
public final class HSSFErrorConstants extends ErrorConstants { | |||
} |
@@ -39,7 +39,8 @@ public final class HSSFSheetConditionalFormatting { | |||
/** | |||
* 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 | |||
* <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> | |||
* | |||
* 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 | |||
*/ | |||
public HSSFConditionalFormattingRule createConditionalFormattingRule(String formula) { |
@@ -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; | |||
} | |||
} |
@@ -355,7 +355,7 @@ public abstract class TextShape extends SimpleShape { | |||
*/ | |||
public float getMarginLeft(){ | |||
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(); | |||
return (float)val/EMU_PER_POINT; | |||
} |
@@ -635,27 +635,24 @@ public class Range | |||
/** | |||
* Replace (one instance of) a piece of text with another... | |||
* | |||
* @param pPlaceHolder The text to be replaced (e.g., "${company}") | |||
* @param pValue The replacement text (e.g., "Cognocys, Inc.") | |||
* @param pDocument The <code>HWPFDocument</code> in which the placeholder was found | |||
* @param pStartOffset The offset or index where the <code>CharacterRun</code> begins | |||
* @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, | |||
int pStartOffset, int pPlaceHolderIndex, HWPFDocument pDocument) { | |||
int absPlaceHolderIndex = pStartOffset + pPlaceHolderIndex; | |||
* @param pPlaceHolder The text to be replaced (e.g., "${organization}") | |||
* @param pValue The replacement text (e.g., "Apache Software Foundation") | |||
* @param pOffset The offset or index where the text to be replaced begins | |||
* (relative to/within this <code>Range</code>) | |||
*/ | |||
public void replaceText(String pPlaceHolder, String pValue, int pOffset) | |||
{ | |||
int absPlaceHolderIndex = getStartOffset() + pOffset; | |||
Range subRange = new Range( | |||
absPlaceHolderIndex, | |||
(absPlaceHolderIndex + pPlaceHolder.length()), pDocument | |||
(absPlaceHolderIndex + pPlaceHolder.length()), getDocument() | |||
); | |||
if (subRange.usesUnicode()) { | |||
absPlaceHolderIndex = pStartOffset + (pPlaceHolderIndex * 2); | |||
absPlaceHolderIndex = getStartOffset() + (pOffset * 2); | |||
subRange = new Range( | |||
absPlaceHolderIndex, | |||
(absPlaceHolderIndex + (pPlaceHolder.length() * 2)), | |||
pDocument | |||
getDocument() | |||
); | |||
} | |||
@@ -665,13 +662,13 @@ public class Range | |||
subRange = new Range( | |||
(absPlaceHolderIndex + pValue.length()), | |||
(absPlaceHolderIndex + pPlaceHolder.length() + pValue.length()), | |||
pDocument | |||
getDocument() | |||
); | |||
if (subRange.usesUnicode()) | |||
subRange = new Range( | |||
(absPlaceHolderIndex + (pValue.length() * 2)), | |||
(absPlaceHolderIndex + (pPlaceHolder.length() * 2) + | |||
(pValue.length() * 2)), pDocument | |||
(pValue.length() * 2)), getDocument() | |||
); | |||
subRange.delete(); | |||
@@ -942,4 +939,9 @@ public class Range | |||
return _end; | |||
} | |||
protected HWPFDocument getDocument() { | |||
return _doc; | |||
} | |||
} |
@@ -23,6 +23,7 @@ import junit.framework.TestCase; | |||
import java.io.*; | |||
import java.util.ArrayList; | |||
import java.util.HashMap; | |||
import org.apache.poi.hslf.usermodel.SlideShow; | |||
import org.apache.poi.hslf.record.TextHeaderAtom; | |||
@@ -157,4 +158,46 @@ public class TestTextShape extends TestCase { | |||
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); | |||
} | |||
} |
@@ -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); | |||
} | |||
} |
@@ -17,12 +17,16 @@ | |||
package org.apache.poi.hssf.record; | |||
import junit.framework.AssertionFailedError; | |||
import junit.framework.TestCase; | |||
import org.apache.poi.hssf.record.CFRuleRecord.ComparisonOperator; | |||
import org.apache.poi.hssf.record.cf.BorderFormatting; | |||
import org.apache.poi.hssf.record.cf.FontFormatting; | |||
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.util.HSSFColor; | |||
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) | |||
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) | |||
{ |
@@ -30,7 +30,10 @@ import junit.framework.TestCase; | |||
import org.apache.poi.ss.util.Region; | |||
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.NameRecord; | |||
import org.apache.poi.hssf.record.formula.DeletedArea3DPtg; | |||
import org.apache.poi.util.TempFile; | |||
/** | |||
@@ -990,4 +993,63 @@ public final class TestBugs extends TestCase { | |||
fail(); | |||
} 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); | |||
} | |||
} | |||
} |