https://svn.apache.org:443/repos/asf/poi/trunk ........ r658322 | nick | 2008-05-20 17:37:15 +0100 (Tue, 20 May 2008) | 1 line Fix bug #44977 - Support for AM/PM in excel date formats ........ r658336 | nick | 2008-05-20 17:51:49 +0100 (Tue, 20 May 2008) | 1 line Test which seems to show that bug #44996 is invalid, but not completely sure ........ r658349 | nick | 2008-05-20 17:57:20 +0100 (Tue, 20 May 2008) | 1 line Patch from bug #45001 - Partial fix for HWPF Range.insertBefore() and Range.delete() with unicode characters ........ r658350 | nick | 2008-05-20 18:12:08 +0100 (Tue, 20 May 2008) | 1 line Put abstract write(OutputStream) method on POIDocument ........ r658352 | nick | 2008-05-20 18:17:16 +0100 (Tue, 20 May 2008) | 1 line Patch from bug #45003 - Support embeded HDGF visio documents ........ r658833 | josh | 2008-05-21 20:57:40 +0100 (Wed, 21 May 2008) | 1 line improved toString and refactored toFormulaString on Area(3D)Ptg ........ r658984 | josh | 2008-05-22 04:00:29 +0100 (Thu, 22 May 2008) | 1 line Fixed compiler errors. Other improvements for type safety and immutability. ........ r658986 | josh | 2008-05-22 04:26:25 +0100 (Thu, 22 May 2008) | 1 line Follow on from bug 44675 - regenerated functionMetadata.txt from new ooo excelfileformat.odt ........ r659067 | nick | 2008-05-22 10:51:44 +0100 (Thu, 22 May 2008) | 1 line Example for finding hslf sounds from Yegor ........ r659403 | josh | 2008-05-23 04:56:31 +0100 (Fri, 23 May 2008) | 1 line Fix for 45066 - sheet encoding size mismatch problems ........ r659429 | josh | 2008-05-23 06:28:54 +0100 (Fri, 23 May 2008) | 1 line Fix for bug 45046 - allowed DEFINEDNAME records without EXTERNALBOOK records ........ r659452 | josh | 2008-05-23 07:43:51 +0100 (Fri, 23 May 2008) | 1 line Bug 45041 - improved FormulaParser parse error messages ........ r659455 | josh | 2008-05-23 07:54:46 +0100 (Fri, 23 May 2008) | 1 line Bug 45025 - improved FormulaParser parse error messages (r659452 had wrong bug number) ........ r659462 | josh | 2008-05-23 08:42:14 +0100 (Fri, 23 May 2008) | 1 line Marked out test failure which was fixed by patch for bug 39903 ........ r659478 | josh | 2008-05-23 09:55:48 +0100 (Fri, 23 May 2008) | 1 line Fix for bug 35925 - Missing HSSFColor.TAN from HashTables returned by getIndexHash() and getTripletHash() ........ git-svn-id: https://svn.apache.org/repos/asf/poi/branches/ooxml@659485 13f79535-47bb-0310-9956-ffa450edef68tags/REL_3_5_BETA2
@@ -245,6 +245,7 @@ under the License. | |||
<path id="examples.classpath"> | |||
<path refid="main.classpath"/> | |||
<pathelement location="${main.output.dir}"/> | |||
<pathelement location="${scratchpad.output.dir}"/> | |||
</path> | |||
@@ -44,6 +44,12 @@ | |||
<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-??"> | |||
<action dev="POI-DEVELOPERS" type="add">45025 - improved FormulaParser parse error messages</action> | |||
<action dev="POI-DEVELOPERS" type="add">45046 - allowed EXTERNALBOOK(0x01AE) to be optional in the LinkTable</action> | |||
<action dev="POI-DEVELOPERS" type="add">45066 - fixed sheet encoding size mismatch problems</action> | |||
<action dev="POI-DEVELOPERS" type="add">45003 - Support embeded HDGF visio documents</action> | |||
<action dev="POI-DEVELOPERS" type="fix">45001 - Partial fix for HWPF Range.insertBefore() and Range.delete() with unicode characters</action> | |||
<action dev="POI-DEVELOPERS" type="fix">44977 - Support for AM/PM in excel date formats</action> | |||
<action dev="POI-DEVELOPERS" type="add">Support for specifying a policy to HSSF on missing / blank cells when fetching</action> | |||
<action dev="POI-DEVELOPERS" type="add">44937 - Partial support for extracting Escher images from HWPF files</action> | |||
<action dev="POI-DEVELOPERS" type="fix">44824 - Avoid an infinite loop when reading some HWPF pictures</action> |
@@ -41,6 +41,12 @@ | |||
<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-??"> | |||
<action dev="POI-DEVELOPERS" type="add">45025 - improved FormulaParser parse error messages</action> | |||
<action dev="POI-DEVELOPERS" type="add">45046 - allowed EXTERNALBOOK(0x01AE) to be optional in the LinkTable</action> | |||
<action dev="POI-DEVELOPERS" type="add">45066 - fixed sheet encoding size mismatch problems</action> | |||
<action dev="POI-DEVELOPERS" type="add">45003 - Support embeded HDGF visio documents</action> | |||
<action dev="POI-DEVELOPERS" type="fix">45001 - Partial fix for HWPF Range.insertBefore() and Range.delete() with unicode characters</action> | |||
<action dev="POI-DEVELOPERS" type="fix">44977 - Support for AM/PM in excel date formats</action> | |||
<action dev="POI-DEVELOPERS" type="add">Support for specifying a policy to HSSF on missing / blank cells when fetching</action> | |||
<action dev="POI-DEVELOPERS" type="add">44937 - Partial support for extracting Escher images from HWPF files</action> | |||
<action dev="POI-DEVELOPERS" type="fix">44824 - Avoid an infinite loop when reading some HWPF pictures</action> |
@@ -0,0 +1,80 @@ | |||
/* ==================================================================== | |||
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.hslf.usermodel.examples; | |||
import org.apache.poi.ddf.*; | |||
import org.apache.poi.hslf.model.*; | |||
import org.apache.poi.hslf.record.InteractiveInfo; | |||
import org.apache.poi.hslf.record.InteractiveInfoAtom; | |||
import org.apache.poi.hslf.record.Record; | |||
import org.apache.poi.hslf.usermodel.*; | |||
import java.io.FileInputStream; | |||
import java.util.Iterator; | |||
import java.util.List; | |||
/** | |||
* For each slide iterate over shapes and found associated sound data. | |||
* | |||
* @author Yegor Kozlov | |||
*/ | |||
public class SoundFinder { | |||
public static void main(String[] args) throws Exception { | |||
SlideShow ppt = new SlideShow(new FileInputStream(args[0])); | |||
SoundData[] sounds = ppt.getSoundData(); | |||
Slide[] slide = ppt.getSlides(); | |||
for (int i = 0; i < slide.length; i++) { | |||
Shape[] shape = slide[i].getShapes(); | |||
for (int j = 0; j < shape.length; j++) { | |||
int soundRef = getSoundReference(shape[j]); | |||
if(soundRef != -1) { | |||
System.out.println("Slide["+i+"], shape["+j+"], soundRef: "+soundRef); | |||
System.out.println(" " + sounds[soundRef].getSoundName()); | |||
System.out.println(" " + sounds[soundRef].getSoundType()); | |||
} | |||
} | |||
} | |||
} | |||
/** | |||
* Check if a given shape is associated with a sound. | |||
* @return 0-based reference to a sound in the sound collection | |||
* or -1 if the shape is not associated with a sound | |||
*/ | |||
protected static int getSoundReference(Shape shape){ | |||
int soundRef = -1; | |||
//dive into the shape container and search for InteractiveInfoAtom | |||
EscherContainerRecord spContainer = shape.getSpContainer(); | |||
List spchild = spContainer.getChildRecords(); | |||
for (Iterator it = spchild.iterator(); it.hasNext();) { | |||
EscherRecord obj = (EscherRecord) it.next(); | |||
if (obj.getRecordId() == EscherClientDataRecord.RECORD_ID) { | |||
byte[] data = obj.serialize(); | |||
Record[] records = Record.findChildRecords(data, 8, | |||
data.length - 8); | |||
for (int j = 0; j < records.length; j++) { | |||
if (records[j] instanceof InteractiveInfo) { | |||
InteractiveInfoAtom info = ((InteractiveInfo)records[j]).getInteractiveInfoAtom(); | |||
if (info.getAction() == InteractiveInfoAtom.ACTION_MEDIA) { | |||
soundRef = info.getSoundRef(); | |||
} | |||
} | |||
} | |||
} | |||
} | |||
return soundRef; | |||
} | |||
} |
@@ -20,6 +20,7 @@ package org.apache.poi; | |||
import java.io.ByteArrayInputStream; | |||
import java.io.ByteArrayOutputStream; | |||
import java.io.IOException; | |||
import java.io.OutputStream; | |||
import java.util.Iterator; | |||
import java.util.List; | |||
@@ -191,6 +192,11 @@ public abstract class POIDocument { | |||
System.err.println("Couldn't write property set with name " + name + " as not supported by HPSF yet"); | |||
} | |||
} | |||
/** | |||
* Writes the document out to the specified output stream | |||
*/ | |||
public abstract void write(OutputStream out) throws IOException; | |||
/** | |||
* Copies nodes from one POIFS to the other minus the excepts |
@@ -55,7 +55,7 @@ public final class FormulaParser { | |||
*/ | |||
static final class FormulaParseException extends RuntimeException { | |||
// This class was given package scope until it would become clear that it is useful to | |||
// general client code. | |||
// general client code. | |||
public FormulaParseException(String msg) { | |||
super(msg); | |||
} | |||
@@ -127,42 +127,34 @@ public final class FormulaParser { | |||
// Just return if so and reset 'look' to something to keep | |||
// SkipWhitespace from spinning | |||
look = (char)0; | |||
} | |||
} | |||
pointer++; | |||
//System.out.println("Got char: "+ look); | |||
} | |||
/** Report What Was Expected */ | |||
private RuntimeException expected(String s) { | |||
String msg = "Parse error near char " + (pointer-1) + "'" + look + "'" | |||
String msg = "Parse error near char " + (pointer-1) + " '" + look + "'" | |||
+ " in specified formula '" + formulaString + "'. Expected " | |||
+ s; | |||
return new FormulaParseException(msg); | |||
} | |||
/** Recognize an Alpha Character */ | |||
private boolean IsAlpha(char c) { | |||
return Character.isLetter(c) || c == '$' || c=='_'; | |||
} | |||
/** Recognize a Decimal Digit */ | |||
private boolean IsDigit(char c) { | |||
//System.out.println("Checking digit for"+c); | |||
return Character.isDigit(c); | |||
} | |||
/** Recognize an Alphanumeric */ | |||
private boolean IsAlNum(char c) { | |||
return (IsAlpha(c) || IsDigit(c)); | |||
} | |||
/** Recognize White Space */ | |||
private boolean IsWhite( char c) { | |||
return (c ==' ' || c== TAB); | |||
@@ -178,7 +170,7 @@ public final class FormulaParser { | |||
/** | |||
* Consumes the next input character if it is equal to the one specified otherwise throws an | |||
* unchecked exception. This method does <b>not</b> consume whitespace (before or after the | |||
* matched character). | |||
* matched character). | |||
*/ | |||
private void Match(char x) { | |||
if (look != x) { | |||
@@ -218,7 +210,6 @@ public final class FormulaParser { | |||
return Token.toString(); | |||
} | |||
/** Get a Number */ | |||
private String GetNum() { | |||
StringBuffer value = new StringBuffer(); | |||
@@ -281,18 +272,18 @@ public final class FormulaParser { | |||
// This can be either a cell ref or a named range | |||
// Try to spot which it is | |||
boolean cellRef = CELL_REFERENCE_PATTERN.matcher(name).matches(); | |||
if (cellRef) { | |||
return new ReferencePtg(name); | |||
} | |||
for(int i = 0; i < book.getNumberOfNames(); i++) { | |||
// named range name matching is case insensitive | |||
if(book.getNameAt(i).getNameName().equalsIgnoreCase(name)) { | |||
if(book.getNameAt(i).getNameName().equalsIgnoreCase(name)) { | |||
return new NamePtg(name, book); | |||
} | |||
} | |||
throw new FormulaParseException("Found reference to named range \"" | |||
throw new FormulaParseException("Found reference to named range \"" | |||
+ name + "\", but that named range wasn't defined!"); | |||
} | |||
@@ -307,19 +298,19 @@ public final class FormulaParser { | |||
/** | |||
* Note - Excel function names are 'case aware but not case sensitive'. This method may end | |||
* up creating a defined name record in the workbook if the specified name is not an internal | |||
* Excel function, and has not been encountered before. | |||
* | |||
* @param name case preserved function name (as it was entered/appeared in the formula). | |||
* Excel function, and has not been encountered before. | |||
* | |||
* @param name case preserved function name (as it was entered/appeared in the formula). | |||
*/ | |||
private Ptg function(String name) { | |||
int numArgs =0 ; | |||
// Note regarding parameter - | |||
// Note regarding parameter - | |||
if(!AbstractFunctionPtg.isInternalFunctionName(name)) { | |||
// external functions get a Name token which points to a defined name record | |||
NamePtg nameToken = new NamePtg(name, this.book); | |||
// in the token tree, the name is more or less the first argument | |||
numArgs++; | |||
numArgs++; | |||
tokens.add(nameToken); | |||
} | |||
//average 2 args per function | |||
@@ -477,26 +468,25 @@ public final class FormulaParser { | |||
private static boolean isArgumentDelimiter(char ch) { | |||
return ch == ',' || ch == ')'; | |||
} | |||
/** get arguments to a function */ | |||
private int Arguments(List argumentPointers) { | |||
SkipWhite(); | |||
if(look == ')') { | |||
return 0; | |||
} | |||
boolean missedPrevArg = true; | |||
int numArgs = 0; | |||
while(true) { | |||
while (true) { | |||
SkipWhite(); | |||
if(isArgumentDelimiter(look)) { | |||
if(missedPrevArg) { | |||
if (isArgumentDelimiter(look)) { | |||
if (missedPrevArg) { | |||
tokens.add(new MissingArgPtg()); | |||
addArgumentPointer(argumentPointers); | |||
numArgs++; | |||
} | |||
if(look == ')') { | |||
if (look == ')') { | |||
break; | |||
} | |||
Match(','); | |||
@@ -507,6 +497,10 @@ public final class FormulaParser { | |||
addArgumentPointer(argumentPointers); | |||
numArgs++; | |||
missedPrevArg = false; | |||
SkipWhite(); | |||
if (!isArgumentDelimiter(look)) { | |||
throw expected("',' or ')'"); | |||
} | |||
} | |||
return numArgs; | |||
} | |||
@@ -524,7 +518,7 @@ public final class FormulaParser { | |||
tokens.add(new PowerPtg()); | |||
} | |||
} | |||
private void percentFactor() { | |||
tokens.add(parseSimpleFactor()); | |||
while(true) { | |||
@@ -536,8 +530,8 @@ public final class FormulaParser { | |||
tokens.add(new PercentPtg()); | |||
} | |||
} | |||
/** | |||
* factors (without ^ or % ) | |||
*/ | |||
@@ -561,9 +555,6 @@ public final class FormulaParser { | |||
return new ParenthesisPtg(); | |||
case '"': | |||
return parseStringLiteral(); | |||
case ',': | |||
case ')': | |||
return new MissingArgPtg(); // TODO - not quite the right place to recognise a missing arg | |||
} | |||
if (IsAlpha(look) || look == '\''){ | |||
return parseIdent(); | |||
@@ -707,10 +698,9 @@ public final class FormulaParser { | |||
} | |||
private StringPtg parseStringLiteral() | |||
{ | |||
private StringPtg parseStringLiteral() { | |||
Match('"'); | |||
StringBuffer token = new StringBuffer(); | |||
while (true) { | |||
if (look == '"') { | |||
@@ -745,7 +735,7 @@ public final class FormulaParser { | |||
return; // finished with Term | |||
} | |||
} | |||
private void comparisonExpression() { | |||
concatExpression(); | |||
while (true) { | |||
@@ -787,7 +777,7 @@ public final class FormulaParser { | |||
} | |||
return new LessThanPtg(); | |||
} | |||
private void concatExpression() { | |||
additiveExpression(); | |||
@@ -801,7 +791,7 @@ public final class FormulaParser { | |||
tokens.add(new ConcatPtg()); | |||
} | |||
} | |||
/** Parse and Translate an Expression */ | |||
private void additiveExpression() { | |||
@@ -838,8 +828,9 @@ end; | |||
**/ | |||
/** API call to execute the parsing of the formula | |||
* | |||
/** | |||
* API call to execute the parsing of the formula | |||
* @deprecated use Ptg[] FormulaParser.parse(String, HSSFWorkbook) directly | |||
*/ | |||
public void parse() { | |||
pointer=0; | |||
@@ -847,8 +838,8 @@ end; | |||
comparisonExpression(); | |||
if(pointer <= formulaLength) { | |||
String msg = "Unused input [" + formulaString.substring(pointer-1) | |||
+ "] after attempting to parse the formula [" + formulaString + "]"; | |||
String msg = "Unused input [" + formulaString.substring(pointer-1) | |||
+ "] after attempting to parse the formula [" + formulaString + "]"; | |||
throw new FormulaParseException(msg); | |||
} | |||
} | |||
@@ -863,11 +854,12 @@ end; | |||
* a result of the parsing | |||
*/ | |||
public Ptg[] getRPNPtg() { | |||
return getRPNPtg(FORMULA_TYPE_CELL); | |||
return getRPNPtg(FORMULA_TYPE_CELL); | |||
} | |||
public Ptg[] getRPNPtg(int formulaType) { | |||
Node node = createTree(); | |||
// RVA is for 'operand class': 'reference', 'value', 'array' | |||
setRootLevelRVA(node, formulaType); | |||
setParameterRVA(node,formulaType); | |||
return (Ptg[]) tokens.toArray(new Ptg[0]); | |||
@@ -948,7 +940,7 @@ end; | |||
} | |||
} | |||
/** | |||
* Convience method which takes in a list then passes it to the | |||
* Convenience method which takes in a list then passes it to the | |||
* other toFormulaString signature. | |||
* @param book workbook for 3D and named references | |||
* @param lptgs list of Ptg, can be null or empty | |||
@@ -963,7 +955,7 @@ end; | |||
return retval; | |||
} | |||
/** | |||
* Convience method which takes in a list then passes it to the | |||
* Convenience method which takes in a list then passes it to the | |||
* other toFormulaString signature. Works on the current | |||
* workbook for 3D and named references | |||
* @param lptgs list of Ptg, can be null or empty | |||
@@ -1011,7 +1003,7 @@ end; | |||
continue; | |||
// but if it ever did, care must be taken: | |||
// tAttrSpace comes *before* the operand it applies to, which may be consistent | |||
// with how the formula text appears but is against the RPN ordering assumed here | |||
// with how the formula text appears but is against the RPN ordering assumed here | |||
} | |||
if (attrPtg.isSemiVolatile()) { | |||
// similar to tAttrSpace - RPN is violated | |||
@@ -1038,7 +1030,7 @@ end; | |||
stack.push(o.toFormulaString(operands)); | |||
} | |||
if(stack.isEmpty()) { | |||
// inspection of the code above reveals that every stack.pop() is followed by a | |||
// inspection of the code above reveals that every stack.pop() is followed by a | |||
// stack.push(). So this is either an internal error or impossible. | |||
throw new IllegalStateException("Stack underflow"); | |||
} |
@@ -41,7 +41,7 @@ import org.apache.poi.hssf.record.SupBookRecord; | |||
* | |||
* In BIFF8 the Link Table consists of | |||
* <ul> | |||
* <li>one or more EXTERNALBOOK Blocks<p/> | |||
* <li>zero or more EXTERNALBOOK Blocks<p/> | |||
* each consisting of | |||
* <ul> | |||
* <li>exactly one EXTERNALBOOK (0x01AE) record</li> | |||
@@ -55,7 +55,7 @@ import org.apache.poi.hssf.record.SupBookRecord; | |||
* </li> | |||
* </ul> | |||
* </li> | |||
* <li>exactly one EXTERNSHEET (0x0017) record</li> | |||
* <li>zero or one EXTERNSHEET (0x0017) record</li> | |||
* <li>zero or more DEFINEDNAME (0x0018) records</li> | |||
* </ul> | |||
* | |||
@@ -63,6 +63,7 @@ import org.apache.poi.hssf.record.SupBookRecord; | |||
* @author Josh Micich | |||
*/ | |||
final class LinkTable { | |||
// TODO make this class into a record aggregate | |||
private static final class CRNBlock { | |||
@@ -79,8 +80,8 @@ final class LinkTable { | |||
_crns = crns; | |||
} | |||
public CRNRecord[] getCrns() { | |||
return (CRNRecord[]) _crns.clone(); | |||
} | |||
return (CRNRecord[]) _crns.clone(); | |||
} | |||
} | |||
private static final class ExternalBookBlock { | |||
@@ -136,16 +137,19 @@ final class LinkTable { | |||
while(rs.peekNextClass() == SupBookRecord.class) { | |||
temp.add(new ExternalBookBlock(rs)); | |||
} | |||
if(temp.size() < 1) { | |||
throw new RuntimeException("Need at least one EXTERNALBOOK blocks"); | |||
} | |||
_externalBookBlocks = new ExternalBookBlock[temp.size()]; | |||
temp.toArray(_externalBookBlocks); | |||
temp.clear(); | |||
// If link table is present, there is always 1 of ExternSheetRecord | |||
Record next = rs.getNext(); | |||
_externSheetRecord = (ExternSheetRecord)next; | |||
if (_externalBookBlocks.length > 0) { | |||
// If any ExternalBookBlock present, there is always 1 of ExternSheetRecord | |||
Record next = rs.getNext(); | |||
_externSheetRecord = (ExternSheetRecord) next; | |||
} else { | |||
_externSheetRecord = null; | |||
} | |||
_definedNames = new ArrayList(); | |||
// collect zero or more DEFINEDNAMEs id=0x18 | |||
while(rs.peekNextClass() == NameRecord.class) { | |||
@@ -222,7 +226,7 @@ final class LinkTable { | |||
public void addName(NameRecord name) { | |||
_definedNames.add(name); | |||
// TODO - this is messy | |||
// TODO - this is messy | |||
// Not the most efficient way but the other way was causing too many bugs | |||
int idx = findFirstRecordLocBySid(ExternSheetRecord.sid); | |||
if (idx == -1) idx = findFirstRecordLocBySid(SupBookRecord.sid); | |||
@@ -242,8 +246,8 @@ final class LinkTable { | |||
public int getSheetIndexFromExternSheetIndex(int externSheetNumber) { | |||
if (externSheetNumber >= _externSheetRecord.getNumOfREFStructures()) { | |||
return -1; | |||
} | |||
return -1; | |||
} | |||
return _externSheetRecord.getREFRecordAt(externSheetNumber).getIndexToFirstSupBook(); | |||
} | |||
@@ -265,7 +269,7 @@ final class LinkTable { | |||
ExternSheetSubRecord esr = _externSheetRecord.getREFRecordAt(i); | |||
if (esr.getIndexToFirstSupBook() == sheetNumber | |||
&& esr.getIndexToLastSupBook() == sheetNumber){ | |||
&& esr.getIndexToLastSupBook() == sheetNumber){ | |||
return i; | |||
} | |||
} |
@@ -96,8 +96,8 @@ public final class Sheet implements Model { | |||
protected List condFormatting = new ArrayList(); | |||
/** Add an UncalcedRecord if not true indicating formulas have not been calculated */ | |||
protected boolean uncalced = false; | |||
protected boolean _isUncalced = false; | |||
public static final byte PANE_LOWER_RIGHT = (byte)0; | |||
public static final byte PANE_UPPER_RIGHT = (byte)1; | |||
public static final byte PANE_LOWER_LEFT = (byte)2; | |||
@@ -162,7 +162,7 @@ public final class Sheet implements Model { | |||
} | |||
} | |||
else if (rec.getSid() == UncalcedRecord.sid) { | |||
retval.uncalced = true; | |||
retval._isUncalced = true; | |||
} | |||
else if (rec.getSid() == DimensionsRecord.sid) | |||
{ | |||
@@ -329,16 +329,8 @@ public final class Sheet implements Model { | |||
} | |||
} | |||
retval.records = records; | |||
// if (retval.rows == null) | |||
// { | |||
// retval.rows = new RowRecordsAggregate(); | |||
// } | |||
retval.checkCells(); | |||
retval.checkRows(); | |||
// if (retval.cells == null) | |||
// { | |||
// retval.cells = new ValueRecordsAggregate(); | |||
// } | |||
if (log.check( POILogger.DEBUG )) | |||
log.log(POILogger.DEBUG, "sheet createSheet (existing file) exited"); | |||
return retval; | |||
@@ -816,17 +808,17 @@ public final class Sheet implements Model { | |||
// Once the rows have been found in the list of records, start | |||
// writing out the blocked row information. This includes the DBCell references | |||
if (record instanceof RowRecordsAggregate) { | |||
pos += ((RowRecordsAggregate)record).serialize(pos, data, cells); // rec.length; | |||
pos += ((RowRecordsAggregate)record).serialize(pos, data, cells); | |||
} else if (record instanceof ValueRecordsAggregate) { | |||
//Do nothing here. The records were serialized during the RowRecordAggregate block serialization | |||
} else { | |||
pos += record.serialize(pos, data ); // rec.length; | |||
pos += record.serialize(pos, data ); | |||
} | |||
// If the BOF record was just serialized then add the IndexRecord | |||
if (record.getSid() == BOFRecord.sid) { | |||
// Add an optional UncalcedRecord | |||
if (uncalced) { | |||
if (_isUncalced) { | |||
UncalcedRecord rec = new UncalcedRecord(); | |||
pos += rec.serialize(pos, data); | |||
} | |||
@@ -837,31 +829,10 @@ public final class Sheet implements Model { | |||
pos += serializeIndexRecord(k, pos, data); | |||
} | |||
} | |||
//// uncomment to test record sizes //// | |||
// System.out.println( record.getClass().getName() ); | |||
// byte[] data2 = new byte[record.getRecordSize()]; | |||
// record.serialize(0, data2 ); // rec.length; | |||
// if (LittleEndian.getUShort(data2, 2) != record.getRecordSize() - 4 | |||
// && record instanceof RowRecordsAggregate == false | |||
// && record instanceof ValueRecordsAggregate == false | |||
// && record instanceof EscherAggregate == false) | |||
// { | |||
// throw new RuntimeException("Blah!!! Size off by " + ( LittleEndian.getUShort(data2, 2) - record.getRecordSize() - 4) + " records."); | |||
// } | |||
//asd: int len = record.serialize(pos + offset, data ); | |||
///// DEBUG BEGIN ///// | |||
//asd: if (len != record.getRecordSize()) | |||
//asd: throw new IllegalStateException("Record size does not match serialized bytes. Serialized size = " + len + " but getRecordSize() returns " + record.getRecordSize() + ". Record object is " + record.getClass()); | |||
///// DEBUG END ///// | |||
//asd: pos += len; // rec.length; | |||
} | |||
if (log.check( POILogger.DEBUG )) | |||
if (log.check( POILogger.DEBUG )) { | |||
log.log(POILogger.DEBUG, "Sheet.serialize returning "); | |||
} | |||
return pos-offset; | |||
} | |||
@@ -875,10 +846,17 @@ public final class Sheet implements Model { | |||
for (int j = BOFRecordIndex+1; j < records.size(); j++) | |||
{ | |||
Record tmpRec = (( Record ) records.get(j)); | |||
if (tmpRec instanceof RowRecordsAggregate) | |||
break; | |||
if (tmpRec instanceof UncalcedRecord) { | |||
continue; | |||
} | |||
if (tmpRec instanceof RowRecordsAggregate) { | |||
break; | |||
} | |||
sheetRecSize+= tmpRec.getRecordSize(); | |||
} | |||
if (_isUncalced) { | |||
sheetRecSize += UncalcedRecord.getStaticRecordSize(); | |||
} | |||
//Add the references to the DBCells in the IndexRecord (one for each block) | |||
int blockCount = rows.getRowBlockCount(); | |||
//Calculate the size of this IndexRecord | |||
@@ -2017,31 +1995,33 @@ public final class Sheet implements Model { | |||
{ | |||
int retval = 0; | |||
for ( int k = 0; k < records.size(); k++ ) | |||
{ | |||
retval += ( (Record) records.get( k ) ).getRecordSize(); | |||
for ( int k = 0; k < records.size(); k++) { | |||
Record record = (Record) records.get(k); | |||
if (record instanceof UncalcedRecord) { | |||
// skip the UncalcedRecord if present, it's only encoded if the isUncalced flag is set | |||
continue; | |||
} | |||
retval += record.getRecordSize(); | |||
} | |||
//Add space for the IndexRecord | |||
if (rows != null) { | |||
final int blocks = rows.getRowBlockCount(); | |||
retval += IndexRecord.getRecordSizeForBlockCount(blocks); | |||
//Add space for the DBCell records | |||
//Once DBCell per block. | |||
//8 bytes per DBCell (non variable section) | |||
//2 bytes per row reference | |||
retval += (8 * blocks); | |||
for (Iterator itr = rows.getIterator(); itr.hasNext();) { | |||
RowRecord row = (RowRecord)itr.next(); | |||
if (cells != null && cells.rowHasCells(row.getRowNumber())) | |||
retval += 2; | |||
// Add space for the IndexRecord and DBCell records | |||
final int nBlocks = rows.getRowBlockCount(); | |||
int nRows = 0; | |||
if (cells != null) { | |||
for (Iterator itr = rows.getIterator(); itr.hasNext();) { | |||
RowRecord row = (RowRecord)itr.next(); | |||
if (cells.rowHasCells(row.getRowNumber())) { | |||
nRows++; | |||
} | |||
} | |||
} | |||
retval += IndexRecord.getRecordSizeForBlockCount(nBlocks); | |||
retval += DBCellRecord.calculateSizeOfRecords(nBlocks, nRows); | |||
} | |||
// Add space for UncalcedRecord | |||
if (uncalced) { | |||
if (_isUncalced) { | |||
retval += UncalcedRecord.getStaticRecordSize(); | |||
} | |||
return retval; | |||
} | |||
@@ -2518,13 +2498,13 @@ public final class Sheet implements Model { | |||
* @return whether an uncalced record must be inserted or not at generation | |||
*/ | |||
public boolean getUncalced() { | |||
return uncalced; | |||
return _isUncalced; | |||
} | |||
/** | |||
* @param uncalced whether an uncalced record must be inserted or not at generation | |||
*/ | |||
public void setUncalced(boolean uncalced) { | |||
this.uncalced = uncalced; | |||
this._isUncalced = uncalced; | |||
} | |||
/** |
@@ -191,12 +191,11 @@ public class Workbook implements Model | |||
case ExternSheetRecord.sid : | |||
throw new RuntimeException("Extern sheet is part of LinkTable"); | |||
case NameRecord.sid : | |||
throw new RuntimeException("DEFINEDNAME is part of LinkTable"); | |||
case SupBookRecord.sid : | |||
// LinkTable can start with either of these | |||
if (log.check( POILogger.DEBUG )) | |||
log.log(DEBUG, "found SupBook record at " + k); | |||
retval.linkTable = new LinkTable(recs, k, retval.records); | |||
// retval.records.supbookpos = k; | |||
k+=retval.linkTable.getRecordCount() - 1; | |||
continue; | |||
case FormatRecord.sid : |
@@ -1,4 +1,3 @@ | |||
/* ==================================================================== | |||
Licensed to the Apache Software Foundation (ASF) under one or more | |||
contributor license agreements. See the NOTICE file distributed with | |||
@@ -15,7 +14,6 @@ | |||
See the License for the specific language governing permissions and | |||
limitations under the License. | |||
==================================================================== */ | |||
package org.apache.poi.hssf.record; | |||
@@ -29,10 +27,7 @@ import org.apache.poi.util.LittleEndian; | |||
* @author Jason Height | |||
* @version 2.0-pre | |||
*/ | |||
public class DBCellRecord | |||
extends Record | |||
{ | |||
public final class DBCellRecord extends Record { | |||
public final static int BLOCK_SIZE = 32; | |||
public final static short sid = 0xd7; | |||
private int field_1_row_offset; | |||
@@ -46,7 +41,6 @@ public class DBCellRecord | |||
* Constructs a DBCellRecord and sets its fields appropriately | |||
* @param in the RecordInputstream to read the record from | |||
*/ | |||
public DBCellRecord(RecordInputStream in) | |||
{ | |||
super(in); | |||
@@ -78,7 +72,6 @@ public class DBCellRecord | |||
* | |||
* @param offset offset to the start of the first cell in the next DBCell block | |||
*/ | |||
public void setRowOffset(int offset) | |||
{ | |||
field_1_row_offset = offset; | |||
@@ -108,7 +101,6 @@ public class DBCellRecord | |||
* | |||
* @return rowoffset to the start of the first cell in the next DBCell block | |||
*/ | |||
public int getRowOffset() | |||
{ | |||
return field_1_row_offset; | |||
@@ -120,7 +112,6 @@ public class DBCellRecord | |||
* @param index of the cell offset to retrieve | |||
* @return celloffset from the celloffset array | |||
*/ | |||
public short getCellOffsetAt(int index) | |||
{ | |||
return field_2_cell_offsets[ index ]; | |||
@@ -131,7 +122,6 @@ public class DBCellRecord | |||
* | |||
* @return number of cell offsets | |||
*/ | |||
public int getNumCellOffsets() | |||
{ | |||
return field_2_cell_offsets.length; | |||
@@ -175,9 +165,15 @@ public class DBCellRecord | |||
return 8 + (getNumCellOffsets() * 2); | |||
} | |||
/** Returns the size of a DBCellRecord when it needs to reference a certain number of rows*/ | |||
public static int getRecordSizeForRows(int rows) { | |||
return 8 + (rows * 2); | |||
/** | |||
* @returns the size of the group of <tt>DBCellRecord</tt>s needed to encode | |||
* the specified number of blocks and rows | |||
*/ | |||
public static int calculateSizeOfRecords(int nBlocks, int nRows) { | |||
// One DBCell per block. | |||
// 8 bytes per DBCell (non variable section) | |||
// 2 bytes per row reference | |||
return nBlocks * 8 + nRows * 2; | |||
} | |||
public short getSid() |
@@ -27,7 +27,7 @@ import org.apache.poi.util.LittleEndian; | |||
/** | |||
* Title: Area 3D Ptg - 3D referecnce (Sheet + Area)<P> | |||
* Title: Area 3D Ptg - 3D reference (Sheet + Area)<P> | |||
* Description: Defined a area in Extern Sheet. <P> | |||
* REFERENCE: <P> | |||
* @author Libin Roman (Vista Portal LDT. Developer) | |||
@@ -35,7 +35,6 @@ import org.apache.poi.util.LittleEndian; | |||
* @author Jason Height (jheight at chariot dot net dot au) | |||
* @version 1.0-pre | |||
*/ | |||
public class Area3DPtg extends Ptg implements AreaI | |||
{ | |||
public final static byte sid = 0x3b; | |||
@@ -84,23 +83,15 @@ public class Area3DPtg extends Ptg implements AreaI | |||
setExternSheetIndex(externalSheetIndex); | |||
} | |||
public String toString() | |||
{ | |||
StringBuffer buffer = new StringBuffer(); | |||
buffer.append( "AreaPtg\n" ); | |||
buffer.append( "Index to Extern Sheet = " + getExternSheetIndex() ).append( "\n" ); | |||
buffer.append( "firstRow = " + getFirstRow() ).append( "\n" ); | |||
buffer.append( "lastRow = " + getLastRow() ).append( "\n" ); | |||
buffer.append( "firstCol = " + getFirstColumn() ).append( "\n" ); | |||
buffer.append( "lastCol = " + getLastColumn() ).append( "\n" ); | |||
buffer.append( "firstColRel= " | |||
+ isFirstRowRelative() ).append( "\n" ); | |||
buffer.append( "lastColRowRel = " | |||
+ isLastRowRelative() ).append( "\n" ); | |||
buffer.append( "firstColRel = " + isFirstColRelative() ).append( "\n" ); | |||
buffer.append( "lastColRel = " + isLastColRelative() ).append( "\n" ); | |||
return buffer.toString(); | |||
public String toString() { | |||
StringBuffer sb = new StringBuffer(); | |||
sb.append(getClass().getName()); | |||
sb.append(" ["); | |||
sb.append("sheetIx=").append(getExternSheetIndex()); | |||
sb.append(" ! "); | |||
sb.append(AreaReference.formatAsString(this)); | |||
sb.append("]"); | |||
return sb.toString(); | |||
} | |||
public void writeBytes( byte[] array, int offset ) | |||
@@ -284,7 +275,7 @@ public class Area3DPtg extends Ptg implements AreaI | |||
} | |||
// Now the normal area bit | |||
retval.append( AreaPtg.toFormulaString(this, book) ); | |||
retval.append(AreaReference.formatAsString(this)); | |||
// All done | |||
return retval.toString(); | |||
@@ -326,6 +317,7 @@ public class Area3DPtg extends Ptg implements AreaI | |||
public int hashCode() | |||
{ | |||
// TODO - hashCode seems to be unused | |||
int result; | |||
result = (int) field_1_index_extern_sheet; | |||
result = 29 * result + (int) field_2_first_row; |
@@ -114,23 +114,13 @@ public class AreaPtg extends Ptg implements AreaI { | |||
return "AreaPtg"; | |||
} | |||
public String toString() | |||
{ | |||
StringBuffer buffer = new StringBuffer(); | |||
buffer.append(getAreaPtgName()); | |||
buffer.append("\n"); | |||
buffer.append("firstRow = " + getFirstRow()).append("\n"); | |||
buffer.append("lastRow = " + getLastRow()).append("\n"); | |||
buffer.append("firstCol = " + getFirstColumn()).append("\n"); | |||
buffer.append("lastCol = " + getLastColumn()).append("\n"); | |||
buffer.append("firstColRowRel= " | |||
+ isFirstRowRelative()).append("\n"); | |||
buffer.append("lastColRowRel = " | |||
+ isLastRowRelative()).append("\n"); | |||
buffer.append("firstColRel = " + isFirstColRelative()).append("\n"); | |||
buffer.append("lastColRel = " + isLastColRelative()).append("\n"); | |||
return buffer.toString(); | |||
public String toString() { | |||
StringBuffer sb = new StringBuffer(); | |||
sb.append(getClass().getName()); | |||
sb.append(" ["); | |||
sb.append(AreaReference.formatAsString(this)); | |||
sb.append("]"); | |||
return sb.toString(); | |||
} | |||
public void writeBytes(byte [] array, int offset) { | |||
@@ -307,19 +297,8 @@ public class AreaPtg extends Ptg implements AreaI { | |||
field_4_last_column = column; | |||
} | |||
public String toFormulaString(Workbook book) | |||
{ | |||
return toFormulaString(this, book); | |||
} | |||
protected static String toFormulaString(AreaI area, Workbook book) { | |||
CellReference topLeft = new CellReference(area.getFirstRow(),area.getFirstColumn(),!area.isFirstRowRelative(),!area.isFirstColRelative()); | |||
CellReference botRight = new CellReference(area.getLastRow(),area.getLastColumn(),!area.isLastRowRelative(),!area.isLastColRelative()); | |||
if(AreaReference.isWholeColumnReference(topLeft, botRight)) { | |||
return (new AreaReference(topLeft, botRight)).formatAsString(); | |||
} else { | |||
return topLeft.formatAsString() + ":" + botRight.formatAsString(); | |||
} | |||
public String toFormulaString(Workbook book) { | |||
return AreaReference.formatAsString(this); | |||
} | |||
public byte getDefaultOperandClass() { |
@@ -15,12 +15,6 @@ | |||
limitations under the License. | |||
==================================================================== */ | |||
/* | |||
* HSSFWorkbook.java | |||
* | |||
* Created on September 30, 2001, 3:37 PM | |||
*/ | |||
package org.apache.poi.hssf.usermodel; | |||
import java.io.ByteArrayInputStream; | |||
@@ -81,7 +75,6 @@ import org.apache.poi.util.POILogger; | |||
* @author Shawn Laubach (slaubach at apache dot org) | |||
* @version 2.0-pre | |||
*/ | |||
public class HSSFWorkbook extends POIDocument implements org.apache.poi.ss.usermodel.Workbook | |||
{ | |||
private static final int DEBUG = POILogger.DEBUG; | |||
@@ -105,7 +98,7 @@ public class HSSFWorkbook extends POIDocument implements org.apache.poi.ss.userm | |||
* this holds the HSSFSheet objects attached to this workbook | |||
*/ | |||
protected ArrayList sheets; | |||
protected List _sheets; | |||
/** | |||
* this holds the HSSFName objects attached to this workbook | |||
@@ -159,7 +152,7 @@ public class HSSFWorkbook extends POIDocument implements org.apache.poi.ss.userm | |||
{ | |||
super(null, null); | |||
workbook = book; | |||
sheets = new ArrayList( INITIAL_CAPACITY ); | |||
_sheets = new ArrayList( INITIAL_CAPACITY ); | |||
names = new ArrayList( INITIAL_CAPACITY ); | |||
} | |||
@@ -250,7 +243,7 @@ public class HSSFWorkbook extends POIDocument implements org.apache.poi.ss.userm | |||
this.directory = null; | |||
} | |||
sheets = new ArrayList(INITIAL_CAPACITY); | |||
_sheets = new ArrayList(INITIAL_CAPACITY); | |||
names = new ArrayList(INITIAL_CAPACITY); | |||
// Grab the data from the workbook stream, however | |||
@@ -280,7 +273,7 @@ public class HSSFWorkbook extends POIDocument implements org.apache.poi.ss.userm | |||
HSSFSheet hsheet = new HSSFSheet(this, sheet); | |||
sheets.add(hsheet); | |||
_sheets.add(hsheet); | |||
// workbook.setSheetName(sheets.size() -1, "Sheet"+sheets.size()); | |||
} | |||
@@ -378,12 +371,12 @@ public class HSSFWorkbook extends POIDocument implements org.apache.poi.ss.userm | |||
*/ | |||
public void setSheetOrder(String sheetname, int pos ) { | |||
sheets.add(pos,sheets.remove(getSheetIndex(sheetname))); | |||
_sheets.add(pos,_sheets.remove(getSheetIndex(sheetname))); | |||
workbook.setSheetOrder(sheetname, pos); | |||
} | |||
private void validateSheetIndex(int index) { | |||
int lastSheetIx = sheets.size() - 1; | |||
int lastSheetIx = _sheets.size() - 1; | |||
if (index < 0 || index > lastSheetIx) { | |||
throw new IllegalArgumentException("Sheet index (" | |||
+ index +") is out of range (0.." + lastSheetIx + ")"); | |||
@@ -397,7 +390,7 @@ public class HSSFWorkbook extends POIDocument implements org.apache.poi.ss.userm | |||
public void setSelectedTab(int index) { | |||
validateSheetIndex(index); | |||
int nSheets = sheets.size(); | |||
int nSheets = _sheets.size(); | |||
for (int i=0; i<nSheets; i++) { | |||
getSheetAt(i).setSelected(i == index); | |||
} | |||
@@ -415,7 +408,7 @@ public class HSSFWorkbook extends POIDocument implements org.apache.poi.ss.userm | |||
for (int i = 0; i < indexes.length; i++) { | |||
validateSheetIndex(indexes[i]); | |||
} | |||
int nSheets = sheets.size(); | |||
int nSheets = _sheets.size(); | |||
for (int i=0; i<nSheets; i++) { | |||
boolean bSelect = false; | |||
for (int j = 0; j < indexes.length; j++) { | |||
@@ -437,7 +430,7 @@ public class HSSFWorkbook extends POIDocument implements org.apache.poi.ss.userm | |||
public void setActiveSheet(int index) { | |||
validateSheetIndex(index); | |||
int nSheets = sheets.size(); | |||
int nSheets = _sheets.size(); | |||
for (int i=0; i<nSheets; i++) { | |||
getSheetAt(i).setActive(i == index); | |||
} | |||
@@ -509,19 +502,15 @@ public class HSSFWorkbook extends POIDocument implements org.apache.poi.ss.userm | |||
* set the sheet name. | |||
* Will throw IllegalArgumentException if the name is greater than 31 chars | |||
* or contains /\?*[] | |||
* @param sheet number (0 based) | |||
* @param sheetIx number (0 based) | |||
*/ | |||
public void setSheetName(int sheet, String name) | |||
public void setSheetName(int sheetIx, String name) | |||
{ | |||
if (workbook.doesContainsSheetName( name, sheet )) | |||
if (workbook.doesContainsSheetName( name, sheetIx )) { | |||
throw new IllegalArgumentException( "The workbook already contains a sheet with this name" ); | |||
if (sheet > (sheets.size() - 1)) | |||
{ | |||
throw new RuntimeException("Sheet out of bounds"); | |||
} | |||
workbook.setSheetName( sheet, name); | |||
validateSheetIndex(sheetIx); | |||
workbook.setSheetName(sheetIx, name); | |||
} | |||
@@ -533,15 +522,12 @@ public class HSSFWorkbook extends POIDocument implements org.apache.poi.ss.userm | |||
* or contains /\?*[] | |||
* @param sheet number (0 based) | |||
*/ | |||
public void setSheetName( int sheet, String name, short encoding ) | |||
public void setSheetName(int sheetIx, String name, short encoding) | |||
{ | |||
if (workbook.doesContainsSheetName( name, sheet )) | |||
if (workbook.doesContainsSheetName( name, sheetIx )) { | |||
throw new IllegalArgumentException( "The workbook already contains a sheet with this name" ); | |||
if (sheet > (sheets.size() - 1)) | |||
{ | |||
throw new RuntimeException("Sheet out of bounds"); | |||
} | |||
validateSheetIndex(sheetIx); | |||
switch ( encoding ) { | |||
case ENCODING_COMPRESSED_UNICODE: | |||
@@ -553,51 +539,39 @@ public class HSSFWorkbook extends POIDocument implements org.apache.poi.ss.userm | |||
throw new RuntimeException( "Unsupported encoding" ); | |||
} | |||
workbook.setSheetName( sheet, name, encoding ); | |||
workbook.setSheetName( sheetIx, name, encoding ); | |||
} | |||
/** | |||
* get the sheet name | |||
* @param sheet Number | |||
* @param sheetIx Number | |||
* @return Sheet name | |||
*/ | |||
public String getSheetName(int sheet) | |||
public String getSheetName(int sheetIx) | |||
{ | |||
if (sheet > (sheets.size() - 1)) | |||
{ | |||
throw new RuntimeException("Sheet out of bounds"); | |||
} | |||
return workbook.getSheetName(sheet); | |||
validateSheetIndex(sheetIx); | |||
return workbook.getSheetName(sheetIx); | |||
} | |||
/** | |||
* check whether a sheet is hidden | |||
* @param sheet Number | |||
* @param sheetIx Number | |||
* @return True if sheet is hidden | |||
*/ | |||
public boolean isSheetHidden(int sheet) { | |||
if (sheet > (sheets.size() - 1)) | |||
{ | |||
throw new RuntimeException("Sheet out of bounds"); | |||
} | |||
return workbook.isSheetHidden(sheet); | |||
public boolean isSheetHidden(int sheetIx) { | |||
validateSheetIndex(sheetIx); | |||
return workbook.isSheetHidden(sheetIx); | |||
} | |||
/** | |||
* Hide or unhide a sheet | |||
* | |||
* @param sheetnum The sheet number | |||
* @param sheetIx The sheet index | |||
* @param hidden True to mark the sheet as hidden, false otherwise | |||
*/ | |||
public void setSheetHidden(int sheet, boolean hidden) { | |||
if (sheet > (sheets.size() - 1)) | |||
{ | |||
throw new RuntimeException("Sheet out of bounds"); | |||
} | |||
workbook.setSheetHidden(sheet,hidden); | |||
public void setSheetHidden(int sheetIx, boolean hidden) { | |||
validateSheetIndex(sheetIx); | |||
workbook.setSheetHidden(sheetIx, hidden); | |||
} | |||
/* | |||
@@ -619,12 +593,12 @@ public class HSSFWorkbook extends POIDocument implements org.apache.poi.ss.userm | |||
/** Returns the index of the given sheet | |||
* @param sheet the sheet to look up | |||
* @return index of the sheet (0 based) | |||
* @return index of the sheet (0 based). <tt>-1</tt> if not found | |||
*/ | |||
public int getSheetIndex(org.apache.poi.ss.usermodel.Sheet sheet) | |||
{ | |||
for(int i=0; i<sheets.size(); i++) { | |||
if(sheets.get(i) == sheet) { | |||
for(int i=0; i<_sheets.size(); i++) { | |||
if(_sheets.get(i) == sheet) { | |||
return i; | |||
} | |||
} | |||
@@ -653,9 +627,9 @@ public class HSSFWorkbook extends POIDocument implements org.apache.poi.ss.userm | |||
{ | |||
HSSFSheet sheet = new HSSFSheet(this); | |||
sheets.add(sheet); | |||
workbook.setSheetName(sheets.size() - 1, "Sheet" + (sheets.size() - 1)); | |||
boolean isOnlySheet = sheets.size() == 1; | |||
_sheets.add(sheet); | |||
workbook.setSheetName(_sheets.size() - 1, "Sheet" + (_sheets.size() - 1)); | |||
boolean isOnlySheet = _sheets.size() == 1; | |||
sheet.setSelected(isOnlySheet); | |||
sheet.setActive(isOnlySheet); | |||
return sheet; | |||
@@ -669,13 +643,13 @@ public class HSSFWorkbook extends POIDocument implements org.apache.poi.ss.userm | |||
public HSSFSheet cloneSheet(int sheetNum) { | |||
validateSheetIndex(sheetNum); | |||
HSSFSheet srcSheet = (HSSFSheet) sheets.get(sheetNum); | |||
HSSFSheet srcSheet = (HSSFSheet) _sheets.get(sheetNum); | |||
String srcName = workbook.getSheetName(sheetNum); | |||
HSSFSheet clonedSheet = srcSheet.cloneSheet(this); | |||
clonedSheet.setSelected(false); | |||
clonedSheet.setActive(false); | |||
sheets.add(clonedSheet); | |||
_sheets.add(clonedSheet); | |||
int i = 1; | |||
while (true) { | |||
// Try and find the next sheet name that is unique | |||
@@ -689,7 +663,7 @@ public class HSSFWorkbook extends POIDocument implements org.apache.poi.ss.userm | |||
//If the sheet name is unique, then set it otherwise move on to the next number. | |||
if (workbook.getSheetIndex(name) == -1) { | |||
workbook.setSheetName(sheets.size()-1, name); | |||
workbook.setSheetName(_sheets.size()-1, name); | |||
break; | |||
} | |||
} | |||
@@ -710,14 +684,14 @@ public class HSSFWorkbook extends POIDocument implements org.apache.poi.ss.userm | |||
public HSSFSheet createSheet(String sheetname) | |||
{ | |||
if (workbook.doesContainsSheetName( sheetname, sheets.size() )) | |||
if (workbook.doesContainsSheetName( sheetname, _sheets.size() )) | |||
throw new IllegalArgumentException( "The workbook already contains a sheet of this name" ); | |||
HSSFSheet sheet = new HSSFSheet(this); | |||
sheets.add(sheet); | |||
workbook.setSheetName(sheets.size() - 1, sheetname); | |||
boolean isOnlySheet = sheets.size() == 1; | |||
_sheets.add(sheet); | |||
workbook.setSheetName(_sheets.size() - 1, sheetname); | |||
boolean isOnlySheet = _sheets.size() == 1; | |||
sheet.setSelected(isOnlySheet); | |||
sheet.setActive(isOnlySheet); | |||
return sheet; | |||
@@ -730,13 +704,19 @@ public class HSSFWorkbook extends POIDocument implements org.apache.poi.ss.userm | |||
public int getNumberOfSheets() | |||
{ | |||
return sheets.size(); | |||
return _sheets.size(); | |||
} | |||
public int getSheetIndexFromExternSheetIndex(int externSheetNumber) { | |||
return workbook.getSheetIndexFromExternSheetIndex(externSheetNumber); | |||
} | |||
private HSSFSheet[] getSheets() { | |||
HSSFSheet[] result = new HSSFSheet[_sheets.size()]; | |||
_sheets.toArray(result); | |||
return result; | |||
} | |||
/** | |||
* Get the HSSFSheet object at the given index. | |||
* @param index of the sheet number (0-based physical & logical) | |||
@@ -745,7 +725,7 @@ public class HSSFWorkbook extends POIDocument implements org.apache.poi.ss.userm | |||
public HSSFSheet getSheetAt(int index) | |||
{ | |||
return (HSSFSheet) sheets.get(index); | |||
return (HSSFSheet) _sheets.get(index); | |||
} | |||
/** | |||
@@ -758,13 +738,13 @@ public class HSSFWorkbook extends POIDocument implements org.apache.poi.ss.userm | |||
{ | |||
HSSFSheet retval = null; | |||
for (int k = 0; k < sheets.size(); k++) | |||
for (int k = 0; k < _sheets.size(); k++) | |||
{ | |||
String sheetname = workbook.getSheetName(k); | |||
if (sheetname.equalsIgnoreCase(name)) | |||
{ | |||
retval = (HSSFSheet) sheets.get(k); | |||
retval = (HSSFSheet) _sheets.get(k); | |||
} | |||
} | |||
return retval; | |||
@@ -793,11 +773,11 @@ public class HSSFWorkbook extends POIDocument implements org.apache.poi.ss.userm | |||
boolean wasActive = getSheetAt(index).isActive(); | |||
boolean wasSelected = getSheetAt(index).isSelected(); | |||
sheets.remove(index); | |||
_sheets.remove(index); | |||
workbook.removeSheet(index); | |||
// set the remaining active/selected sheet | |||
int nSheets = sheets.size(); | |||
int nSheets = _sheets.size(); | |||
if (nSheets < 1) { | |||
// nothing more to do if there are no sheets left | |||
return; | |||
@@ -1173,48 +1153,47 @@ public class HSSFWorkbook extends POIDocument implements org.apache.poi.ss.userm | |||
public byte[] getBytes() | |||
{ | |||
if (log.check( POILogger.DEBUG )) | |||
if (log.check( POILogger.DEBUG )) { | |||
log.log(DEBUG, "HSSFWorkbook.getBytes()"); | |||
} | |||
HSSFSheet[] sheets = getSheets(); | |||
int nSheets = sheets.length; | |||
// before getting the workbook size we must tell the sheets that | |||
// serialization is about to occur. | |||
for (int k = 0; k < sheets.size(); k++) | |||
((HSSFSheet) sheets.get(k)).getSheet().preSerialize(); | |||
int wbsize = workbook.getSize(); | |||
for (int i = 0; i < nSheets; i++) { | |||
sheets[i].getSheet().preSerialize(); | |||
} | |||
// log.debug("REMOVEME: old sizing method "+workbook.serialize().length); | |||
// ArrayList sheetbytes = new ArrayList(sheets.size()); | |||
int totalsize = wbsize; | |||
int totalsize = workbook.getSize(); | |||
for (int k = 0; k < sheets.size(); k++) | |||
{ | |||
// pre-calculate all the sheet sizes and set BOF indexes | |||
int[] estimatedSheetSizes = new int[nSheets]; | |||
for (int k = 0; k < nSheets; k++) { | |||
workbook.setSheetBof(k, totalsize); | |||
totalsize += ((HSSFSheet) sheets.get(k)).getSheet().getSize(); | |||
int sheetSize = sheets[k].getSheet().getSize(); | |||
estimatedSheetSizes[k] = sheetSize; | |||
totalsize += sheetSize; | |||
} | |||
/* if (totalsize < 4096) | |||
{ | |||
totalsize = 4096; | |||
}*/ | |||
byte[] retval = new byte[totalsize]; | |||
int pos = workbook.serialize(0, retval); | |||
// System.arraycopy(wb, 0, retval, 0, wb.length); | |||
for (int k = 0; k < sheets.size(); k++) | |||
{ | |||
// byte[] sb = (byte[])sheetbytes.get(k); | |||
// System.arraycopy(sb, 0, retval, pos, sb.length); | |||
int len = ((HSSFSheet) sheets.get(k)).getSheet().serialize(pos, | |||
retval); | |||
pos += len; // sb.length; | |||
for (int k = 0; k < nSheets; k++) { | |||
int serializedSize = sheets[k].getSheet().serialize(pos, retval); | |||
if (serializedSize != estimatedSheetSizes[k]) { | |||
// Wrong offset values have been passed in the call to setSheetBof() above. | |||
// For books with more than one sheet, this discrepancy would cause excel | |||
// to report errors and loose data while reading the workbook | |||
throw new IllegalStateException("Actual serialized sheet size (" + serializedSize | |||
+ ") differs from pre-calculated size (" + estimatedSheetSizes[k] | |||
+ ") for sheet (" + k + ")"); | |||
// TODO - add similar sanity check to ensure that Sheet.serializeIndexRecord() does not write mis-aligned offsets either | |||
} | |||
pos += serializedSize; | |||
} | |||
/* for (int k = pos; k < totalsize; k++) | |||
{ | |||
retval[k] = 0; | |||
}*/ | |||
return retval; | |||
} | |||
@@ -15,12 +15,13 @@ | |||
limitations under the License. | |||
==================================================================== */ | |||
package org.apache.poi.hssf.util; | |||
import java.util.ArrayList; | |||
import java.util.StringTokenizer; | |||
import org.apache.poi.hssf.record.formula.AreaI; | |||
public final class AreaReference { | |||
/** The character (!) that separates sheet names from cell references */ | |||
@@ -50,13 +51,13 @@ public final class AreaReference { | |||
// Special handling for whole-column references | |||
if(parts.length == 2 && parts[0].length() == 1 && | |||
parts[1].length() == 1 && | |||
parts[0].charAt(0) >= 'A' && parts[0].charAt(0) <= 'Z' && | |||
parts[1].charAt(0) >= 'A' && parts[1].charAt(0) <= 'Z') { | |||
// Represented internally as x$1 to x$65536 | |||
// which is the maximum range of rows | |||
parts[0] = parts[0] + "$1"; | |||
parts[1] = parts[1] + "$65536"; | |||
parts[1].length() == 1 && | |||
parts[0].charAt(0) >= 'A' && parts[0].charAt(0) <= 'Z' && | |||
parts[1].charAt(0) >= 'A' && parts[1].charAt(0) <= 'Z') { | |||
// Represented internally as x$1 to x$65536 | |||
// which is the maximum range of rows | |||
parts[0] = parts[0] + "$1"; | |||
parts[1] = parts[1] + "$65536"; | |||
} | |||
_firstCell = new CellReference(parts[0]); | |||
@@ -74,9 +75,9 @@ public final class AreaReference { | |||
* Creates an area ref from a pair of Cell References. | |||
*/ | |||
public AreaReference(CellReference topLeft, CellReference botRight) { | |||
_firstCell = topLeft; | |||
_lastCell = botRight; | |||
_isSingleCell = false; | |||
_firstCell = topLeft; | |||
_lastCell = botRight; | |||
_isSingleCell = false; | |||
} | |||
/** | |||
@@ -98,17 +99,17 @@ public final class AreaReference { | |||
* such as C:C or D:G ? | |||
*/ | |||
public static boolean isWholeColumnReference(CellReference topLeft, CellReference botRight) { | |||
// These are represented as something like | |||
// C$1:C$65535 or D$1:F$0 | |||
// i.e. absolute from 1st row to 0th one | |||
if(topLeft.getRow() == 0 && topLeft.isRowAbsolute() && | |||
botRight.getRow() == 65535 && botRight.isRowAbsolute()) { | |||
return true; | |||
} | |||
return false; | |||
// These are represented as something like | |||
// C$1:C$65535 or D$1:F$0 | |||
// i.e. absolute from 1st row to 0th one | |||
if(topLeft.getRow() == 0 && topLeft.isRowAbsolute() && | |||
botRight.getRow() == 65535 && botRight.isRowAbsolute()) { | |||
return true; | |||
} | |||
return false; | |||
} | |||
public boolean isWholeColumnReference() { | |||
return isWholeColumnReference(_firstCell, _lastCell); | |||
return isWholeColumnReference(_firstCell, _lastCell); | |||
} | |||
/** | |||
@@ -155,26 +156,26 @@ public final class AreaReference { | |||
* Returns a reference to every cell covered by this area | |||
*/ | |||
public CellReference[] getAllReferencedCells() { | |||
// Special case for single cell reference | |||
if(_isSingleCell) { | |||
return new CellReference[] { _firstCell, }; | |||
} | |||
// Special case for single cell reference | |||
if(_isSingleCell) { | |||
return new CellReference[] { _firstCell, }; | |||
} | |||
// Interpolate between the two | |||
// Interpolate between the two | |||
int minRow = Math.min(_firstCell.getRow(), _lastCell.getRow()); | |||
int maxRow = Math.max(_firstCell.getRow(), _lastCell.getRow()); | |||
int minCol = Math.min(_firstCell.getCol(), _lastCell.getCol()); | |||
int maxCol = Math.max(_firstCell.getCol(), _lastCell.getCol()); | |||
int maxRow = Math.max(_firstCell.getRow(), _lastCell.getRow()); | |||
int minCol = Math.min(_firstCell.getCol(), _lastCell.getCol()); | |||
int maxCol = Math.max(_firstCell.getCol(), _lastCell.getCol()); | |||
String sheetName = _firstCell.getSheetName(); | |||
ArrayList refs = new ArrayList(); | |||
for(int row=minRow; row<=maxRow; row++) { | |||
for(int col=minCol; col<=maxCol; col++) { | |||
CellReference ref = new CellReference(sheetName, row, col, _firstCell.isRowAbsolute(), _firstCell.isColAbsolute()); | |||
refs.add(ref); | |||
} | |||
} | |||
return (CellReference[])refs.toArray(new CellReference[refs.size()]); | |||
ArrayList refs = new ArrayList(); | |||
for(int row=minRow; row<=maxRow; row++) { | |||
for(int col=minCol; col<=maxCol; col++) { | |||
CellReference ref = new CellReference(sheetName, row, col, _firstCell.isRowAbsolute(), _firstCell.isColAbsolute()); | |||
refs.add(ref); | |||
} | |||
} | |||
return (CellReference[])refs.toArray(new CellReference[refs.size()]); | |||
} | |||
/** | |||
@@ -189,14 +190,14 @@ public final class AreaReference { | |||
* @return the text representation of this area reference as it would appear in a formula. | |||
*/ | |||
public String formatAsString() { | |||
// Special handling for whole-column references | |||
if(isWholeColumnReference()) { | |||
return | |||
CellReference.convertNumToColString(_firstCell.getCol()) | |||
+ ":" + | |||
CellReference.convertNumToColString(_lastCell.getCol()); | |||
} | |||
// Special handling for whole-column references | |||
if(isWholeColumnReference()) { | |||
return | |||
CellReference.convertNumToColString(_firstCell.getCol()) | |||
+ ":" + | |||
CellReference.convertNumToColString(_lastCell.getCol()); | |||
} | |||
StringBuffer sb = new StringBuffer(32); | |||
sb.append(_firstCell.formatAsString()); | |||
if(!_isSingleCell) { | |||
@@ -210,6 +211,18 @@ public final class AreaReference { | |||
} | |||
return sb.toString(); | |||
} | |||
/** | |||
* Formats a 2-D area as it would appear in a formula. See formatAsString() (no-arg) | |||
*/ | |||
public static String formatAsString(AreaI area) { | |||
CellReference topLeft = new CellReference(area.getFirstRow(),area.getFirstColumn(),!area.isFirstRowRelative(),!area.isFirstColRelative()); | |||
CellReference botRight = new CellReference(area.getLastRow(),area.getLastColumn(),!area.isLastRowRelative(),!area.isLastColRelative()); | |||
if(isWholeColumnReference(topLeft, botRight)) { | |||
return (new AreaReference(topLeft, botRight)).formatAsString(); | |||
} | |||
return topLeft.formatAsString() + ":" + botRight.formatAsString(); | |||
} | |||
public String toString() { | |||
StringBuffer sb = new StringBuffer(64); | |||
sb.append(getClass().getName()).append(" ["); |
@@ -15,16 +15,16 @@ | |||
limitations under the License. | |||
==================================================================== */ | |||
package org.apache.poi.hssf.util; | |||
import java.lang.reflect.Field; | |||
import java.util.Hashtable; | |||
import org.apache.poi.ss.usermodel.Color; | |||
/** | |||
* Intends to provide support for the very evil index to triplet issue and | |||
* will likely replace the color contants interface for HSSF 2.0. | |||
* will likely replace the color constants interface for HSSF 2.0. | |||
* This class contains static inner class members for representing colors. | |||
* Each color has an index (for the standard palette in Excel (tm) ), | |||
* native (RGB) triplet and string triplet. The string triplet is as the | |||
@@ -35,14 +35,10 @@ import org.apache.poi.ss.usermodel.Color; | |||
* @author Andrew C. Oliver (acoliver at apache dot org) | |||
* @author Brian Sanders (bsanders at risklabs dot com) - full default color palette | |||
*/ | |||
public class HSSFColor implements Color | |||
{ | |||
private final static int PALETTE_SIZE = 56; | |||
private final static int DISTINCT_COLOR_COUNT = 46; | |||
public class HSSFColor implements Color { | |||
// TODO make subclass instances immutable | |||
/** Creates a new instance of HSSFColor */ | |||
public HSSFColor() | |||
{ | |||
} | |||
@@ -54,87 +50,86 @@ public class HSSFColor implements Color | |||
* it takes to create it once per request but you will not hold onto it | |||
* if you have none of those requests. | |||
* | |||
* @return a hashtable containing all colors mapped to their excel-style | |||
* pallette index | |||
* @return a hashtable containing all colors keyed by <tt>Integer</tt> excel-style palette indexes | |||
*/ | |||
public final static Hashtable getIndexHash() { | |||
Hashtable hash = new Hashtable(PALETTE_SIZE); | |||
hash.put(new Integer(HSSFColor.BLACK.index), new HSSFColor.BLACK()); | |||
hash.put(new Integer(HSSFColor.BROWN.index), new HSSFColor.BROWN()); | |||
hash.put(new Integer(HSSFColor.OLIVE_GREEN.index), | |||
new HSSFColor.OLIVE_GREEN()); | |||
hash.put(new Integer(HSSFColor.DARK_GREEN.index), new HSSFColor.DARK_GREEN()); | |||
hash.put(new Integer(HSSFColor.DARK_TEAL.index), new HSSFColor.DARK_TEAL()); | |||
hash.put(new Integer(HSSFColor.DARK_BLUE.index), new HSSFColor.DARK_BLUE()); | |||
hash.put(new Integer(HSSFColor.DARK_BLUE.index2), new HSSFColor.DARK_BLUE()); | |||
hash.put(new Integer(HSSFColor.INDIGO.index), new HSSFColor.INDIGO()); | |||
hash.put(new Integer(HSSFColor.GREY_80_PERCENT.index), | |||
new HSSFColor.GREY_80_PERCENT()); | |||
hash.put(new Integer(HSSFColor.ORANGE.index), new HSSFColor.ORANGE()); | |||
hash.put(new Integer(HSSFColor.DARK_YELLOW.index), | |||
new HSSFColor.DARK_YELLOW()); | |||
hash.put(new Integer(HSSFColor.GREEN.index), new HSSFColor.GREEN()); | |||
hash.put(new Integer(HSSFColor.TEAL.index), new HSSFColor.TEAL()); | |||
hash.put(new Integer(HSSFColor.TEAL.index2), new HSSFColor.TEAL()); | |||
hash.put(new Integer(HSSFColor.BLUE.index), new HSSFColor.BLUE()); | |||
hash.put(new Integer(HSSFColor.BLUE.index2), new HSSFColor.BLUE()); | |||
hash.put(new Integer(HSSFColor.BLUE_GREY.index), new HSSFColor.BLUE_GREY()); | |||
hash.put(new Integer(HSSFColor.GREY_50_PERCENT.index), | |||
new HSSFColor.GREY_50_PERCENT()); | |||
hash.put(new Integer(HSSFColor.RED.index), new HSSFColor.RED()); | |||
hash.put(new Integer(HSSFColor.LIGHT_ORANGE.index), | |||
new HSSFColor.LIGHT_ORANGE()); | |||
hash.put(new Integer(HSSFColor.LIME.index), new HSSFColor.LIME()); | |||
hash.put(new Integer(HSSFColor.SEA_GREEN.index), new HSSFColor.SEA_GREEN()); | |||
hash.put(new Integer(HSSFColor.AQUA.index), new HSSFColor.AQUA()); | |||
hash.put(new Integer(HSSFColor.LIGHT_BLUE.index), new HSSFColor.LIGHT_BLUE()); | |||
hash.put(new Integer(HSSFColor.VIOLET.index), new HSSFColor.VIOLET()); | |||
hash.put(new Integer(HSSFColor.VIOLET.index2), new HSSFColor.VIOLET()); | |||
hash.put(new Integer(HSSFColor.GREY_40_PERCENT.index), | |||
new HSSFColor.GREY_40_PERCENT()); | |||
hash.put(new Integer(HSSFColor.PINK.index), new HSSFColor.PINK()); | |||
hash.put(new Integer(HSSFColor.PINK.index2), new HSSFColor.PINK()); | |||
hash.put(new Integer(HSSFColor.GOLD.index), new HSSFColor.GOLD()); | |||
hash.put(new Integer(HSSFColor.YELLOW.index), new HSSFColor.YELLOW()); | |||
hash.put(new Integer(HSSFColor.YELLOW.index2), new HSSFColor.YELLOW()); | |||
hash.put(new Integer(HSSFColor.BRIGHT_GREEN.index), | |||
new HSSFColor.BRIGHT_GREEN()); | |||
hash.put(new Integer(HSSFColor.BRIGHT_GREEN.index2), | |||
new HSSFColor.BRIGHT_GREEN()); | |||
hash.put(new Integer(HSSFColor.TURQUOISE.index), new HSSFColor.TURQUOISE()); | |||
hash.put(new Integer(HSSFColor.TURQUOISE.index2), new HSSFColor.TURQUOISE()); | |||
hash.put(new Integer(HSSFColor.DARK_RED.index), new HSSFColor.DARK_RED()); | |||
hash.put(new Integer(HSSFColor.DARK_RED.index2), new HSSFColor.DARK_RED()); | |||
hash.put(new Integer(HSSFColor.SKY_BLUE.index), new HSSFColor.SKY_BLUE()); | |||
hash.put(new Integer(HSSFColor.PLUM.index), new HSSFColor.PLUM()); | |||
hash.put(new Integer(HSSFColor.PLUM.index2), new HSSFColor.PLUM()); | |||
hash.put(new Integer(HSSFColor.GREY_25_PERCENT.index), | |||
new HSSFColor.GREY_25_PERCENT()); | |||
hash.put(new Integer(HSSFColor.ROSE.index), new HSSFColor.ROSE()); | |||
hash.put(new Integer(HSSFColor.LIGHT_YELLOW.index), | |||
new HSSFColor.LIGHT_YELLOW()); | |||
hash.put(new Integer(HSSFColor.LIGHT_GREEN.index), | |||
new HSSFColor.LIGHT_GREEN()); | |||
hash.put(new Integer(HSSFColor.LIGHT_TURQUOISE.index), | |||
new HSSFColor.LIGHT_TURQUOISE()); | |||
hash.put(new Integer(HSSFColor.LIGHT_TURQUOISE.index2), | |||
new HSSFColor.LIGHT_TURQUOISE()); | |||
hash.put(new Integer(HSSFColor.PALE_BLUE.index), new HSSFColor.PALE_BLUE()); | |||
hash.put(new Integer(HSSFColor.LAVENDER.index), new HSSFColor.LAVENDER()); | |||
hash.put(new Integer(HSSFColor.WHITE.index), new HSSFColor.WHITE()); | |||
hash.put(new Integer(HSSFColor.CORNFLOWER_BLUE.index), | |||
new HSSFColor.CORNFLOWER_BLUE()); | |||
hash.put(new Integer(HSSFColor.LEMON_CHIFFON.index), | |||
new HSSFColor.LEMON_CHIFFON()); | |||
hash.put(new Integer(HSSFColor.MAROON.index), new HSSFColor.MAROON()); | |||
hash.put(new Integer(HSSFColor.ORCHID.index), new HSSFColor.ORCHID()); | |||
hash.put(new Integer(HSSFColor.CORAL.index), new HSSFColor.CORAL()); | |||
hash.put(new Integer(HSSFColor.ROYAL_BLUE.index), new HSSFColor.ROYAL_BLUE()); | |||
hash.put(new Integer(HSSFColor.LIGHT_CORNFLOWER_BLUE.index), | |||
new HSSFColor.LIGHT_CORNFLOWER_BLUE()); | |||
return hash; | |||
return createColorsByIndexMap(); | |||
} | |||
private static Hashtable createColorsByIndexMap() { | |||
HSSFColor[] colors = getAllColors(); | |||
Hashtable result = new Hashtable(colors.length * 3 / 2); | |||
for (int i = 0; i < colors.length; i++) { | |||
HSSFColor color = colors[i]; | |||
Integer index1 = new Integer(color.getIndex()); | |||
if (result.containsKey(index1)) { | |||
HSSFColor prevColor = (HSSFColor)result.get(index1); | |||
throw new RuntimeException("Dup color index (" + index1 | |||
+ ") for colors (" + prevColor.getClass().getName() | |||
+ "),(" + color.getClass().getName() + ")"); | |||
} | |||
result.put(index1, color); | |||
} | |||
for (int i = 0; i < colors.length; i++) { | |||
HSSFColor color = colors[i]; | |||
Integer index2 = getIndex2(color); | |||
if (index2 == null) { | |||
// most colors don't have a second index | |||
continue; | |||
} | |||
if (result.containsKey(index2)) { | |||
if (false) { // Many of the second indexes clash | |||
HSSFColor prevColor = (HSSFColor)result.get(index2); | |||
throw new RuntimeException("Dup color index (" + index2 | |||
+ ") for colors (" + prevColor.getClass().getName() | |||
+ "),(" + color.getClass().getName() + ")"); | |||
} | |||
} | |||
result.put(index2, color); | |||
} | |||
return result; | |||
} | |||
private static Integer getIndex2(HSSFColor color) { | |||
Field f; | |||
try { | |||
f = color.getClass().getDeclaredField("index2"); | |||
} catch (NoSuchFieldException e) { | |||
// can happen because not all colors have a second index | |||
return null; | |||
} | |||
Short s; | |||
try { | |||
s = (Short) f.get(color); | |||
} catch (IllegalArgumentException e) { | |||
throw new RuntimeException(e); | |||
} catch (IllegalAccessException e) { | |||
throw new RuntimeException(e); | |||
} | |||
return new Integer(s.intValue()); | |||
} | |||
private static HSSFColor[] getAllColors() { | |||
return new HSSFColor[] { | |||
new BLACK(), new BROWN(), new OLIVE_GREEN(), new DARK_GREEN(), | |||
new DARK_TEAL(), new DARK_BLUE(), new INDIGO(), new GREY_80_PERCENT(), | |||
new ORANGE(), new DARK_YELLOW(), new GREEN(), new TEAL(), new BLUE(), | |||
new BLUE_GREY(), new GREY_50_PERCENT(), new RED(), new LIGHT_ORANGE(), new LIME(), | |||
new SEA_GREEN(), new AQUA(), new LIGHT_BLUE(), new VIOLET(), new GREY_40_PERCENT(), | |||
new PINK(), new GOLD(), new YELLOW(), new BRIGHT_GREEN(), new TURQUOISE(), | |||
new DARK_RED(), new SKY_BLUE(), new PLUM(), new GREY_25_PERCENT(), new ROSE(), | |||
new LIGHT_YELLOW(), new LIGHT_GREEN(), new LIGHT_TURQUOISE(), new PALE_BLUE(), | |||
new LAVENDER(), new WHITE(), new CORNFLOWER_BLUE(), new LEMON_CHIFFON(), | |||
new MAROON(), new ORCHID(), new CORAL(), new ROYAL_BLUE(), | |||
new LIGHT_CORNFLOWER_BLUE(), new TAN(), | |||
}; | |||
} | |||
/** | |||
@@ -144,73 +139,28 @@ public class HSSFColor implements Color | |||
* it takes to create it once per request but you will not hold onto it | |||
* if you have none of those requests. | |||
* | |||
* @return a hashtable containing all colors mapped to their gnumeric-like | |||
* triplet string | |||
* @return a hashtable containing all colors keyed by String gnumeric-like triplets | |||
*/ | |||
public final static Hashtable getTripletHash() | |||
{ | |||
Hashtable hash = new Hashtable(DISTINCT_COLOR_COUNT); | |||
hash.put(HSSFColor.BLACK.hexString, new HSSFColor.BLACK()); | |||
hash.put(HSSFColor.BROWN.hexString, new HSSFColor.BROWN()); | |||
hash.put(HSSFColor.OLIVE_GREEN.hexString, | |||
new HSSFColor.OLIVE_GREEN()); | |||
hash.put(HSSFColor.DARK_GREEN.hexString, new HSSFColor.DARK_GREEN()); | |||
hash.put(HSSFColor.DARK_TEAL.hexString, new HSSFColor.DARK_TEAL()); | |||
hash.put(HSSFColor.DARK_BLUE.hexString, new HSSFColor.DARK_BLUE()); | |||
hash.put(HSSFColor.INDIGO.hexString, new HSSFColor.INDIGO()); | |||
hash.put(HSSFColor.GREY_80_PERCENT.hexString, | |||
new HSSFColor.GREY_80_PERCENT()); | |||
hash.put(HSSFColor.ORANGE.hexString, new HSSFColor.ORANGE()); | |||
hash.put(HSSFColor.DARK_YELLOW.hexString, | |||
new HSSFColor.DARK_YELLOW()); | |||
hash.put(HSSFColor.GREEN.hexString, new HSSFColor.GREEN()); | |||
hash.put(HSSFColor.TEAL.hexString, new HSSFColor.TEAL()); | |||
hash.put(HSSFColor.BLUE.hexString, new HSSFColor.BLUE()); | |||
hash.put(HSSFColor.BLUE_GREY.hexString, new HSSFColor.BLUE_GREY()); | |||
hash.put(HSSFColor.GREY_50_PERCENT.hexString, | |||
new HSSFColor.GREY_50_PERCENT()); | |||
hash.put(HSSFColor.RED.hexString, new HSSFColor.RED()); | |||
hash.put(HSSFColor.LIGHT_ORANGE.hexString, | |||
new HSSFColor.LIGHT_ORANGE()); | |||
hash.put(HSSFColor.LIME.hexString, new HSSFColor.LIME()); | |||
hash.put(HSSFColor.SEA_GREEN.hexString, new HSSFColor.SEA_GREEN()); | |||
hash.put(HSSFColor.AQUA.hexString, new HSSFColor.AQUA()); | |||
hash.put(HSSFColor.LIGHT_BLUE.hexString, new HSSFColor.LIGHT_BLUE()); | |||
hash.put(HSSFColor.VIOLET.hexString, new HSSFColor.VIOLET()); | |||
hash.put(HSSFColor.GREY_40_PERCENT.hexString, | |||
new HSSFColor.GREY_40_PERCENT()); | |||
hash.put(HSSFColor.PINK.hexString, new HSSFColor.PINK()); | |||
hash.put(HSSFColor.GOLD.hexString, new HSSFColor.GOLD()); | |||
hash.put(HSSFColor.YELLOW.hexString, new HSSFColor.YELLOW()); | |||
hash.put(HSSFColor.BRIGHT_GREEN.hexString, | |||
new HSSFColor.BRIGHT_GREEN()); | |||
hash.put(HSSFColor.TURQUOISE.hexString, new HSSFColor.TURQUOISE()); | |||
hash.put(HSSFColor.DARK_RED.hexString, new HSSFColor.DARK_RED()); | |||
hash.put(HSSFColor.SKY_BLUE.hexString, new HSSFColor.SKY_BLUE()); | |||
hash.put(HSSFColor.PLUM.hexString, new HSSFColor.PLUM()); | |||
hash.put(HSSFColor.GREY_25_PERCENT.hexString, | |||
new HSSFColor.GREY_25_PERCENT()); | |||
hash.put(HSSFColor.ROSE.hexString, new HSSFColor.ROSE()); | |||
hash.put(HSSFColor.LIGHT_YELLOW.hexString, | |||
new HSSFColor.LIGHT_YELLOW()); | |||
hash.put(HSSFColor.LIGHT_GREEN.hexString, | |||
new HSSFColor.LIGHT_GREEN()); | |||
hash.put(HSSFColor.LIGHT_TURQUOISE.hexString, | |||
new HSSFColor.LIGHT_TURQUOISE()); | |||
hash.put(HSSFColor.PALE_BLUE.hexString, new HSSFColor.PALE_BLUE()); | |||
hash.put(HSSFColor.LAVENDER.hexString, new HSSFColor.LAVENDER()); | |||
hash.put(HSSFColor.WHITE.hexString, new HSSFColor.WHITE()); | |||
hash.put(HSSFColor.CORNFLOWER_BLUE.hexString, new HSSFColor.CORNFLOWER_BLUE()); | |||
hash.put(HSSFColor.LEMON_CHIFFON.hexString, new HSSFColor.LEMON_CHIFFON()); | |||
hash.put(HSSFColor.MAROON.hexString, new HSSFColor.MAROON()); | |||
hash.put(HSSFColor.ORCHID.hexString, new HSSFColor.ORCHID()); | |||
hash.put(HSSFColor.CORAL.hexString, new HSSFColor.CORAL()); | |||
hash.put(HSSFColor.ROYAL_BLUE.hexString, new HSSFColor.ROYAL_BLUE()); | |||
hash.put(HSSFColor.LIGHT_CORNFLOWER_BLUE.hexString, | |||
new HSSFColor.LIGHT_CORNFLOWER_BLUE()); | |||
return hash; | |||
return createColorsByHexStringMap(); | |||
} | |||
private static Hashtable createColorsByHexStringMap() { | |||
HSSFColor[] colors = getAllColors(); | |||
Hashtable result = new Hashtable(colors.length * 3 / 2); | |||
for (int i = 0; i < colors.length; i++) { | |||
HSSFColor color = colors[i]; | |||
String hexString = color.getHexString(); | |||
if (result.containsKey(hexString)) { | |||
throw new RuntimeException("Dup color hexString (" + hexString | |||
+ ") for color (" + color.getClass().getName() + ")"); | |||
} | |||
result.put(hexString, color); | |||
} | |||
return result; | |||
} | |||
/** | |||
@@ -1492,7 +1442,7 @@ public class HSSFColor implements Color | |||
return hexString; | |||
} | |||
} | |||
/** | |||
* Class CORNFLOWER_BLUE | |||
*/ | |||
@@ -1521,8 +1471,8 @@ public class HSSFColor implements Color | |||
return hexString; | |||
} | |||
} | |||
/** | |||
* Class LEMON_CHIFFON | |||
*/ | |||
@@ -1551,7 +1501,7 @@ public class HSSFColor implements Color | |||
return hexString; | |||
} | |||
} | |||
/** | |||
* Class MAROON | |||
*/ | |||
@@ -1580,7 +1530,7 @@ public class HSSFColor implements Color | |||
return hexString; | |||
} | |||
} | |||
/** | |||
* Class ORCHID | |||
*/ | |||
@@ -1609,7 +1559,7 @@ public class HSSFColor implements Color | |||
return hexString; | |||
} | |||
} | |||
/** | |||
* Class CORAL | |||
*/ | |||
@@ -1638,7 +1588,7 @@ public class HSSFColor implements Color | |||
return hexString; | |||
} | |||
} | |||
/** | |||
* Class ROYAL_BLUE | |||
*/ | |||
@@ -1667,7 +1617,7 @@ public class HSSFColor implements Color | |||
return hexString; | |||
} | |||
} | |||
/** | |||
* Class LIGHT_CORNFLOWER_BLUE | |||
*/ | |||
@@ -1696,19 +1646,19 @@ public class HSSFColor implements Color | |||
return hexString; | |||
} | |||
} | |||
/** | |||
* Special Default/Normal/Automatic color. | |||
* <p><i>Note:</i> This class is NOT in the default HashTables returned by HSSFColor. | |||
* The index is a special case which is interpreted in the various setXXXColor calls. | |||
* | |||
* | |||
* @author Jason | |||
* | |||
*/ | |||
public final static class AUTOMATIC extends HSSFColor | |||
{ | |||
private static HSSFColor instance = new AUTOMATIC(); | |||
private static HSSFColor instance = new AUTOMATIC(); | |||
public final static short index = 0x40; | |||
public short getIndex() | |||
@@ -1725,7 +1675,7 @@ public class HSSFColor implements Color | |||
{ | |||
return BLACK.hexString; | |||
} | |||
public static HSSFColor getInstance() { | |||
return instance; | |||
} |
@@ -226,7 +226,9 @@ public class DateUtil | |||
// Otherwise, check it's only made up, in any case, of: | |||
// y m d h s - / , . : | |||
if(fs.matches("^[yYmMdDhHsS\\-/,. :]+$")) { | |||
// optionally followed by AM/PM | |||
// optionally followed by AM/PM | |||
if(fs.matches("^[yYmMdDhHsS\\-/,. :]+[ampAMP]*$")) { | |||
return true; | |||
} | |||
@@ -14,7 +14,7 @@ | |||
# limitations under the License. | |||
# Created by (org.apache.poi.hssf.record.formula.function.ExcelFileFormatDocFunctionExtractor) | |||
# from source file 'excelfileformat.odt' (size=355750, crc=0x2FAEA65A) | |||
# from source file 'excelfileformat.odt' (size=356107, md5=0x8f789cb6e75594caf068f8e193004ef4) | |||
# | |||
#Columns: (index, name, minParams, maxParams, returnClass, paramClasses, isVolatile, hasFootnote ) | |||
@@ -37,7 +37,7 @@ | |||
15 SIN 1 1 V V | |||
16 COS 1 1 V V | |||
17 TAN 1 1 V V | |||
18 ARCTAN 1 1 V V | |||
18 ATAN 1 1 V V | |||
19 PI 0 0 V - | |||
20 SQRT 1 1 V V | |||
21 EXP 1 1 V V | |||
@@ -141,8 +141,8 @@ | |||
169 COUNTA 0 30 V R | |||
183 PRODUCT 0 30 V R | |||
184 FACT 1 1 V V | |||
191 DPRODUCT 3 3 V R R R | |||
192 ISNONTEXT 1 1 V V | |||
189 DPRODUCT 3 3 V R R R | |||
190 ISNONTEXT 1 1 V V | |||
193 STDEVP 1 30 V R | |||
194 VARP 1 30 V R | |||
195 DSTDEVP 3 3 V R R R | |||
@@ -184,6 +184,8 @@ | |||
244 INFO 1 1 V V | |||
# New Built-In Sheet Functions in BIFF4 | |||
14 FIXED 2 3 V V V V x | |||
204 USDOLLAR 1 2 V V V x | |||
215 DBCS 1 1 V V x | |||
216 RANK 2 3 V V R V | |||
247 DB 4 5 V V V V V V | |||
252 FREQUENCY 2 2 A R R |
@@ -14,11 +14,9 @@ | |||
# limitations under the License. | |||
# Created by (org.apache.poi.hssf.record.formula.function.ExcelFileFormatDocFunctionExtractor) | |||
# from source file 'excelfileformat.odt' (size=355750, crc=0x2FAEA65A) | |||
# from source file 'excelfileformat.odt' (size=356107, md5=0x8f789cb6e75594caf068f8e193004ef4) | |||
# | |||
#Columns: (index, name, minParams, maxParams, returnClass, paramClasses, isVolatile, hasFootnote ) | |||
# | |||
# + some manual edits ! | |||
# Built-In Sheet Functions in BIFF2 | |||
0 COUNT 0 30 V R | |||
@@ -186,7 +184,7 @@ | |||
244 INFO 1 1 V V | |||
# New Built-In Sheet Functions in BIFF4 | |||
14 FIXED 2 3 V V V V x | |||
204 USDOLLAR 1 1 V V x | |||
204 USDOLLAR 1 2 V V V x | |||
215 DBCS 1 1 V V x | |||
216 RANK 2 3 V V R V | |||
247 DB 4 5 V V V V V V |
@@ -18,6 +18,7 @@ package org.apache.poi.hdgf; | |||
import java.io.FileInputStream; | |||
import java.io.IOException; | |||
import java.io.OutputStream; | |||
import org.apache.poi.POIDocument; | |||
import org.apache.poi.hdgf.chunks.ChunkFactory; | |||
@@ -27,6 +28,7 @@ import org.apache.poi.hdgf.streams.PointerContainingStream; | |||
import org.apache.poi.hdgf.streams.Stream; | |||
import org.apache.poi.hdgf.streams.StringsStream; | |||
import org.apache.poi.hdgf.streams.TrailerStream; | |||
import org.apache.poi.poifs.filesystem.DirectoryNode; | |||
import org.apache.poi.poifs.filesystem.DocumentEntry; | |||
import org.apache.poi.poifs.filesystem.POIFSFileSystem; | |||
import org.apache.poi.util.LittleEndian; | |||
@@ -53,14 +55,17 @@ public class HDGFDiagram extends POIDocument { | |||
private PointerFactory ptrFactory; | |||
public HDGFDiagram(POIFSFileSystem fs) throws IOException { | |||
super(fs); | |||
this(fs.getRoot(), fs); | |||
} | |||
public HDGFDiagram(DirectoryNode dir, POIFSFileSystem fs) throws IOException { | |||
super(dir, fs); | |||
DocumentEntry docProps = | |||
(DocumentEntry)filesystem.getRoot().getEntry("VisioDocument"); | |||
(DocumentEntry)dir.getEntry("VisioDocument"); | |||
// Grab the document stream | |||
_docstream = new byte[docProps.getSize()]; | |||
filesystem.createDocumentInputStream("VisioDocument").read(_docstream); | |||
dir.createDocumentInputStream("VisioDocument").read(_docstream); | |||
// Read in the common POI streams | |||
readProperties(); | |||
@@ -149,6 +154,10 @@ public class HDGFDiagram extends POIDocument { | |||
} | |||
} | |||
public void write(OutputStream out) { | |||
throw new IllegalStateException("Writing is not yet implemented, see http://poi.apache.org/hdgf/"); | |||
} | |||
/** | |||
* For testing only | |||
*/ |
@@ -21,17 +21,18 @@ import java.util.ArrayList; | |||
import java.util.HashMap; | |||
import java.util.Iterator; | |||
import java.util.List; | |||
import java.util.Map; | |||
/** | |||
* This class holds all the FSPA (File Shape Address) structures. | |||
* | |||
* @author Squeeself | |||
*/ | |||
public class FSPATable | |||
public final class FSPATable | |||
{ | |||
protected ArrayList shapes = new ArrayList(); | |||
protected HashMap cps = new HashMap(); | |||
protected List _text; | |||
private final List _shapes = new ArrayList(); | |||
private final Map _shapeIndexesByPropertyStart = new HashMap(); | |||
private final List _text; | |||
public FSPATable(byte[] tableStream, int fcPlcspa, int lcbPlcspa, List tpt) | |||
{ | |||
@@ -46,32 +47,35 @@ public class FSPATable | |||
GenericPropertyNode property = plex.getProperty(i); | |||
FSPA fspa = new FSPA(property.getBytes(), 0); | |||
shapes.add(fspa); | |||
cps.put(Integer.valueOf(property.getStart()), Integer.valueOf(i)); | |||
_shapes.add(fspa); | |||
_shapeIndexesByPropertyStart.put(new Integer(property.getStart()), new Integer(i)); | |||
} | |||
} | |||
public FSPA getFspaFromCp(int cp) | |||
{ | |||
Integer idx = (Integer)cps.get(Integer.valueOf(cp)); | |||
if (idx == null) | |||
Integer idx = (Integer)_shapeIndexesByPropertyStart.get(new Integer(cp)); | |||
if (idx == null) { | |||
return null; | |||
return (FSPA)shapes.get(idx.intValue()); | |||
} | |||
return (FSPA)_shapes.get(idx.intValue()); | |||
} | |||
public List getShapes() | |||
public FSPA[] getShapes() | |||
{ | |||
return shapes; | |||
FSPA[] result = new FSPA[_shapes.size()]; | |||
_shapes.toArray(result); | |||
return result; | |||
} | |||
public String toString() | |||
{ | |||
StringBuffer buf = new StringBuffer(); | |||
buf.append("[FPSA PLC size=").append(shapes.size()).append("]\n"); | |||
for (Iterator it = cps.keySet().iterator(); it.hasNext(); ) | |||
buf.append("[FPSA PLC size=").append(_shapes.size()).append("]\n"); | |||
for (Iterator it = _shapeIndexesByPropertyStart.keySet().iterator(); it.hasNext(); ) | |||
{ | |||
Integer i = (Integer) it.next(); | |||
FSPA fspa = (FSPA) shapes.get(((Integer)cps.get(i)).intValue()); | |||
FSPA fspa = (FSPA) _shapes.get(((Integer)_shapeIndexesByPropertyStart.get(i)).intValue()); | |||
buf.append(" [FC: ").append(i.toString()).append("] "); | |||
buf.append(fspa.toString()); | |||
buf.append("\n"); |
@@ -294,6 +294,16 @@ public class FileInformationBlock extends FIBAbstractType | |||
_longHandler.setLong(FIBLongHandler.CBMAC, cbMac); | |||
} | |||
public int getCcpText() | |||
{ | |||
return _longHandler.getLong(FIBLongHandler.CCPTEXT); | |||
} | |||
public void setCcpText(int ccpText) | |||
{ | |||
_longHandler.setLong(FIBLongHandler.CCPTEXT, ccpText); | |||
} | |||
public void clearOffsetsSizes() | |||
{ | |||
_fieldHandler.clearFields(); |
@@ -90,12 +90,20 @@ public class TextPiece extends PropertyNode implements Comparable | |||
public void adjustForDelete(int start, int length) | |||
{ | |||
if (usesUnicode()) { | |||
start /= 2; | |||
length /= 2; | |||
} | |||
int myStart = getStart(); | |||
int myEnd = getEnd(); | |||
int end = start + length; | |||
/* do we have to delete from this text piece? */ | |||
if (start <= myEnd && end >= myStart) { | |||
/* find where the deleted area overlaps with this text piece */ | |||
int overlapStart = Math.max(myStart, start); | |||
int overlapEnd = Math.min(myEnd, end); |
@@ -226,6 +226,25 @@ public class Range | |||
} | |||
} | |||
/** | |||
* Does any <code>TextPiece</code> in this Range use unicode? | |||
* | |||
* @return true if it does and false if it doesn't | |||
*/ | |||
public boolean usesUnicode() { | |||
initText(); | |||
for (int i = _textStart; i < _textEnd; i++) | |||
{ | |||
TextPiece piece = (TextPiece)_text.get(i); | |||
if (piece.usesUnicode()) | |||
return true; | |||
} | |||
return false; | |||
} | |||
/** | |||
* Gets the text that this Range contains. | |||
* | |||
@@ -306,13 +325,19 @@ public class Range | |||
// Since this is the first item in our list, it is safe to assume that | |||
// _start >= tp.getStart() | |||
int insertIndex = _start - tp.getStart(); | |||
if (tp.usesUnicode()) | |||
insertIndex /= 2; | |||
sb.insert(insertIndex, text); | |||
int adjustedLength = _doc.getTextTable().adjustForInsert(_textStart, text.length()); | |||
_doc.getCharacterTable().adjustForInsert(_charStart, adjustedLength); | |||
_doc.getParagraphTable().adjustForInsert(_parStart, adjustedLength); | |||
_doc.getSectionTable().adjustForInsert(_sectionStart, adjustedLength); | |||
adjustForInsert(text.length()); | |||
// update the FIB.CCPText field | |||
adjustFIB(text.length()); | |||
return getCharacterRun(0); | |||
} | |||
@@ -489,6 +514,7 @@ public class Range | |||
public void delete() | |||
{ | |||
initAll(); | |||
int numSections = _sections.size(); | |||
@@ -519,6 +545,12 @@ public class Range | |||
TextPiece piece = (TextPiece)_text.get(x); | |||
piece.adjustForDelete(_start, _end - _start); | |||
} | |||
// update the FIB.CCPText field | |||
if (usesUnicode()) | |||
adjustFIB(-((_end - _start) / 2)); | |||
else | |||
adjustFIB(-(_end - _start)); | |||
} | |||
/** | |||
@@ -827,6 +859,19 @@ public class Range | |||
_sectionRangeFound = false; | |||
} | |||
/** | |||
* Adjust the value of <code>FIB.CCPText</code> after an insert or a delete... | |||
* | |||
* @param adjustment The (signed) value that should be added to <code>FIB.CCPText</code> | |||
*/ | |||
protected void adjustFIB(int adjustment) { | |||
// update the FIB.CCPText field (this should happen once per adjustment, so we don't want it in | |||
// adjustForInsert() or it would get updated multiple times if the range has a parent) | |||
// without this, OpenOffice.org (v. 2.2.x) does not see all the text in the document | |||
_doc.getFileInformationBlock().setCcpText(_doc.getFileInformationBlock().getCcpText() + adjustment); | |||
} | |||
/** | |||
* adjust this range after an insert happens. | |||
* @param length the length to adjust for | |||
@@ -834,6 +879,7 @@ public class Range | |||
private void adjustForInsert(int length) | |||
{ | |||
_end += length; | |||
reset(); | |||
Range parent = (Range)_parent.get(); | |||
if (parent != null) | |||
@@ -842,4 +888,14 @@ public class Range | |||
} | |||
} | |||
public int getStartOffset() { | |||
return _start; | |||
} | |||
public int getEndOffset() { | |||
return _end; | |||
} | |||
} |
@@ -17,6 +17,7 @@ | |||
package org.apache.poi.hssf.model; | |||
import junit.framework.AssertionFailedError; | |||
import junit.framework.TestCase; | |||
import org.apache.poi.hssf.record.*; | |||
import org.apache.poi.hssf.record.aggregates.ColumnInfoRecordsAggregate; | |||
@@ -351,5 +352,25 @@ public final class TestSheet extends TestCase { | |||
xfindex = sheet.getXFIndexForColAt((short) 10); | |||
assertEquals(DEFAULT_IDX, xfindex); | |||
} | |||
/** | |||
* Prior to bug 45066, POI would get the estimated sheet size wrong | |||
* when an <tt>UncalcedRecord</tt> was present.<p/> | |||
*/ | |||
public void testUncalcSize_bug45066() { | |||
List records = new ArrayList(); | |||
records.add(new BOFRecord()); | |||
records.add(new UncalcedRecord()); | |||
records.add(new EOFRecord()); | |||
Sheet sheet = Sheet.createSheet( records, 0, 0 ); | |||
int estimatedSize = sheet.getSize(); | |||
int serializedSize = sheet.serialize(0, new byte[estimatedSize]); | |||
if (serializedSize != estimatedSize) { | |||
throw new AssertionFailedError("Identified bug 45066 b"); | |||
} | |||
assertEquals(50, serializedSize); | |||
} | |||
} | |||
@@ -26,9 +26,12 @@ import java.io.InputStream; | |||
import java.io.OutputStream; | |||
import java.io.PrintStream; | |||
import java.io.UnsupportedEncodingException; | |||
import java.math.BigInteger; | |||
import java.net.MalformedURLException; | |||
import java.net.URL; | |||
import java.net.URLConnection; | |||
import java.security.MessageDigest; | |||
import java.security.NoSuchAlgorithmException; | |||
import java.util.ArrayList; | |||
import java.util.Arrays; | |||
import java.util.HashMap; | |||
@@ -37,7 +40,6 @@ import java.util.List; | |||
import java.util.Map; | |||
import java.util.Set; | |||
import java.util.Stack; | |||
import java.util.zip.CRC32; | |||
import java.util.zip.ZipException; | |||
import java.util.zip.ZipFile; | |||
@@ -149,7 +151,6 @@ public final class ExcelFileFormatDocFunctionExtractor { | |||
private static final class FunctionDataCollector { | |||
private final Map _allFunctionsByIndex; | |||
private final Map _allFunctionsByName; | |||
private final Set _groupFunctionIndexes; | |||
@@ -184,25 +185,29 @@ public final class ExcelFileFormatDocFunctionExtractor { | |||
_allFunctionsByName.put(funcName, fd); | |||
} | |||
/** | |||
* Some extra validation here. | |||
* Any function which changes definition will have a footnote in the source document | |||
*/ | |||
private void checkRedefinedFunction(boolean hasNote, String funcName, Integer funcIxKey) { | |||
FunctionData fdPrev; | |||
// check by index | |||
fdPrev = (FunctionData) _allFunctionsByIndex.get(funcIxKey); | |||
if(fdPrev != null) { | |||
if(fdPrev.hasFootnote() && hasNote) { | |||
// func def can change if both have a foot-note | |||
_allFunctionsByName.remove(fdPrev.getName()); | |||
} else { | |||
throw new RuntimeException("changing function definition without foot-note"); | |||
if(!fdPrev.hasFootnote() || !hasNote) { | |||
throw new RuntimeException("changing function [" | |||
+ funcIxKey + "] definition without foot-note"); | |||
} | |||
_allFunctionsByName.remove(fdPrev.getName()); | |||
} | |||
// check by name | |||
fdPrev = (FunctionData) _allFunctionsByName.get(funcName); | |||
if(fdPrev != null) { | |||
if(fdPrev.hasFootnote() && hasNote) { | |||
// func def can change if both have a foot-note | |||
_allFunctionsByIndex.remove(new Integer(fdPrev.getIndex())); | |||
} else { | |||
throw new RuntimeException("changing function definition without foot-note"); | |||
if(!fdPrev.hasFootnote() || !hasNote) { | |||
throw new RuntimeException("changing function '" | |||
+ funcName + "' definition without foot-note"); | |||
} | |||
_allFunctionsByIndex.remove(new Integer(fdPrev.getIndex())); | |||
} | |||
} | |||
@@ -237,9 +242,13 @@ public final class ExcelFileFormatDocFunctionExtractor { | |||
private static final String[] TABLE_CELL_RELPATH_NAMES = { | |||
"table:table-row", "table:table-cell", "text:p", | |||
}; | |||
private static final String[] NOTE_REF_RELPATH_NAMES = { | |||
// after May 2008 there was one more style applied to the footnotes | |||
private static final String[] NOTE_REF_RELPATH_NAMES_OLD = { | |||
"table:table-row", "table:table-cell", "text:p", "text:span", "text:note-ref", | |||
}; | |||
private static final String[] NOTE_REF_RELPATH_NAMES = { | |||
"table:table-row", "table:table-cell", "text:p", "text:span", "text:span", "text:note-ref", | |||
}; | |||
private final Stack _elemNameStack; | |||
@@ -368,6 +377,8 @@ public final class ExcelFileFormatDocFunctionExtractor { | |||
} else if(matchesRelPath(TABLE_CELL_RELPATH_NAMES)) { | |||
_textNodeBuffer.setLength(0); | |||
_cellHasNote = false; | |||
} else if(matchesRelPath(NOTE_REF_RELPATH_NAMES_OLD)) { | |||
_cellHasNote = true; | |||
} else if(matchesRelPath(NOTE_REF_RELPATH_NAMES)) { | |||
_cellHasNote = true; | |||
} | |||
@@ -456,6 +467,9 @@ public final class ExcelFileFormatDocFunctionExtractor { | |||
} | |||
private static void processFile(File effDocFile, File outFile) { | |||
if(!effDocFile.exists()) { | |||
throw new RuntimeException("file '" + effDocFile.getAbsolutePath() + "' does not exist"); | |||
} | |||
OutputStream os; | |||
try { | |||
os = new FileOutputStream(outFile); | |||
@@ -475,7 +489,7 @@ public final class ExcelFileFormatDocFunctionExtractor { | |||
ps.println("# Created by (" + genClass.getName() + ")"); | |||
// identify the source file | |||
ps.print("# from source file '" + SOURCE_DOC_FILE_NAME + "'"); | |||
ps.println(" (size=" + effDocFile.length() + ", crc=" + getFileCRC(effDocFile) + ")"); | |||
ps.println(" (size=" + effDocFile.length() + ", md5=" + getFileMD5(effDocFile) + ")"); | |||
ps.println("#"); | |||
ps.println("#Columns: (index, name, minParams, maxParams, returnClass, paramClasses, isVolatile, hasFootnote )"); | |||
ps.println(""); | |||
@@ -490,6 +504,14 @@ public final class ExcelFileFormatDocFunctionExtractor { | |||
throw new RuntimeException(e); | |||
} | |||
ps.close(); | |||
String canonicalOutputFileName; | |||
try { | |||
canonicalOutputFileName = outFile.getCanonicalPath(); | |||
} catch (IOException e) { | |||
throw new RuntimeException(e); | |||
} | |||
System.out.println("Successfully output to '" + canonicalOutputFileName + "'"); | |||
} | |||
private static void outputLicenseHeader(PrintStream ps) { | |||
@@ -519,8 +541,14 @@ public final class ExcelFileFormatDocFunctionExtractor { | |||
/** | |||
* Helps identify the source file | |||
*/ | |||
private static String getFileCRC(File f) { | |||
CRC32 crc = new CRC32(); | |||
private static String getFileMD5(File f) { | |||
MessageDigest m; | |||
try { | |||
m = MessageDigest.getInstance("MD5"); | |||
} catch (NoSuchAlgorithmException e) { | |||
throw new RuntimeException(e); | |||
} | |||
byte[]buf = new byte[2048]; | |||
try { | |||
InputStream is = new FileInputStream(f); | |||
@@ -529,21 +557,17 @@ public final class ExcelFileFormatDocFunctionExtractor { | |||
if(bytesRead<1) { | |||
break; | |||
} | |||
crc.update(buf, 0, bytesRead); | |||
m.update(buf, 0, bytesRead); | |||
} | |||
is.close(); | |||
} catch (IOException e) { | |||
throw new RuntimeException(e); | |||
} | |||
return "0x" + Long.toHexString(crc.getValue()).toUpperCase(); | |||
return "0x" + new BigInteger(1, m.digest()).toString(16); | |||
} | |||
private static File getSourceFile() { | |||
if (false) { | |||
File dir = new File("c:/temp"); | |||
File effDocFile = new File(dir, SOURCE_DOC_FILE_NAME); | |||
return effDocFile; | |||
} | |||
private static File downloadSourceFile() { | |||
URL url; | |||
try { | |||
url = new URL("http://sc.openoffice.org/" + SOURCE_DOC_FILE_NAME); | |||
@@ -557,7 +581,7 @@ public final class ExcelFileFormatDocFunctionExtractor { | |||
URLConnection conn = url.openConnection(); | |||
InputStream is = conn.getInputStream(); | |||
System.out.println("downloading " + url.toExternalForm()); | |||
result = File.createTempFile("excelfileformat", "odt"); | |||
result = File.createTempFile("excelfileformat", ".odt"); | |||
OutputStream os = new FileOutputStream(result); | |||
while(true) { | |||
int bytesRead = is.read(buf); | |||
@@ -577,12 +601,17 @@ public final class ExcelFileFormatDocFunctionExtractor { | |||
public static void main(String[] args) { | |||
File effDocFile = getSourceFile(); | |||
if(!effDocFile.exists()) { | |||
throw new RuntimeException("file '" + effDocFile.getAbsolutePath() + "' does not exist"); | |||
} | |||
File outFile = new File("functionMetadata-asGenerated.txt"); | |||
processFile(effDocFile, outFile); | |||
if (false) { // set true to use local file | |||
File dir = new File("c:/temp"); | |||
File effDocFile = new File(dir, SOURCE_DOC_FILE_NAME); | |||
processFile(effDocFile, outFile); | |||
return; | |||
} | |||
File tempEFFDocFile = downloadSourceFile(); | |||
processFile(tempEFFDocFile, outFile); | |||
tempEFFDocFile.delete(); | |||
} | |||
} |
@@ -21,7 +21,6 @@ import junit.framework.AssertionFailedError; | |||
import junit.framework.TestCase; | |||
import org.apache.poi.hssf.model.FormulaParser; | |||
import org.apache.poi.hssf.model.Workbook; | |||
import org.apache.poi.hssf.record.formula.AbstractFunctionPtg; | |||
import org.apache.poi.hssf.record.formula.FuncPtg; | |||
import org.apache.poi.hssf.record.formula.FuncVarPtg; | |||
@@ -29,7 +28,7 @@ import org.apache.poi.hssf.record.formula.Ptg; | |||
import org.apache.poi.hssf.usermodel.HSSFWorkbook; | |||
/** | |||
* Tests parsing of some built-in functions that were not properly | |||
* registered in POI as bug #44675, #44733 (March/April 2008). | |||
* registered in POI as of bug #44675, #44733 (March/April 2008). | |||
* | |||
* @author Josh Micich | |||
*/ | |||
@@ -76,7 +75,7 @@ public final class TestParseMissingBuiltInFuncs extends TestCase { | |||
} | |||
public void testUsdollar() { | |||
confirmFunc("USDOLLAR(1)", 2, false, 204); | |||
confirmFunc("USDOLLAR(1)", 2, true, 204); | |||
} | |||
public void testDBCS() { |
@@ -17,22 +17,18 @@ | |||
package org.apache.poi.hssf.record.formula.function; | |||
import java.io.File; | |||
import java.io.FileInputStream; | |||
import java.io.IOException; | |||
import java.io.InputStream; | |||
import java.lang.reflect.InvocationTargetException; | |||
import junit.framework.AssertionFailedError; | |||
import junit.framework.TestCase; | |||
import org.apache.poi.hssf.HSSFTestDataSamples; | |||
import org.apache.poi.hssf.record.RecordFormatException; | |||
import org.apache.poi.hssf.usermodel.HSSFSheet; | |||
import org.apache.poi.hssf.usermodel.HSSFWorkbook; | |||
import junit.framework.AssertionFailedError; | |||
import junit.framework.TestCase; | |||
/** | |||
* Tests reading from a sample spreadsheet some built-in functions that were not properly | |||
* registered in POI as bug #44675, #44733 (March/April 2008). | |||
* registered in POI as of bug #44675, #44733 (March/April 2008). | |||
* | |||
* @author Josh Micich | |||
*/ |
@@ -28,7 +28,7 @@ import junit.framework.TestSuite; | |||
public class AllUserModelTests { | |||
public static Test suite() { | |||
TestSuite result = new TestSuite("Tests for org.apache.poi.hssf.usermodel"); | |||
TestSuite result = new TestSuite(AllUserModelTests.class.getName()); | |||
result.addTestSuite(TestBugs.class); | |||
result.addTestSuite(TestCellStyle.class); | |||
@@ -58,6 +58,7 @@ public class AllUserModelTests { | |||
result.addTestSuite(TestHSSFSheetSetOrder.class); | |||
result.addTestSuite(TestHSSFTextbox.class); | |||
result.addTestSuite(TestHSSFWorkbook.class); | |||
result.addTestSuite(TestLinkTable.class); | |||
result.addTestSuite(TestNamedRange.class); | |||
result.addTestSuite(TestOLE2Embeding.class); | |||
result.addTestSuite(TestPOIFSProperties.class); |
@@ -58,6 +58,30 @@ public final class TestHSSFCell extends TestCase { | |||
} | |||
} | |||
public void testSetValues() throws Exception { | |||
HSSFWorkbook book = new HSSFWorkbook(); | |||
HSSFSheet sheet = book.createSheet("test"); | |||
HSSFRow row = sheet.createRow(0); | |||
HSSFCell cell = row.createCell((short)0); | |||
cell.setCellValue(1.2); | |||
assertEquals(1.2, cell.getNumericCellValue(), 0.0001); | |||
assertEquals(HSSFCell.CELL_TYPE_NUMERIC, cell.getCellType()); | |||
cell.setCellValue(false); | |||
assertEquals(false, cell.getBooleanCellValue()); | |||
assertEquals(HSSFCell.CELL_TYPE_BOOLEAN, cell.getCellType()); | |||
cell.setCellValue(new HSSFRichTextString("Foo")); | |||
assertEquals("Foo", cell.getRichStringCellValue().getString()); | |||
assertEquals(HSSFCell.CELL_TYPE_STRING, cell.getCellType()); | |||
cell.setCellValue(new HSSFRichTextString("345")); | |||
assertEquals("345", cell.getRichStringCellValue().getString()); | |||
assertEquals(HSSFCell.CELL_TYPE_STRING, cell.getCellType()); | |||
} | |||
/** | |||
* test that Boolean and Error types (BoolErrRecord) are supported properly. | |||
*/ |
@@ -266,6 +266,8 @@ public class TestHSSFDateUtil extends TestCase { | |||
formats = new String[] { | |||
"yyyy-mm-dd hh:mm:ss", "yyyy/mm/dd HH:MM:SS", | |||
"mm/dd HH:MM", "yy/mmm/dd SS", | |||
"mm/dd HH:MM AM", "mm/dd HH:MM am", | |||
"mm/dd HH:MM PM", "mm/dd HH:MM pm" | |||
}; | |||
for(int i=0; i<formats.length; i++) { | |||
assertTrue( HSSFDateUtil.isADateFormat(formatId, formats[i]) ); |
@@ -36,7 +36,6 @@ import org.apache.poi.hssf.record.VCenterRecord; | |||
import org.apache.poi.hssf.record.WSBoolRecord; | |||
import org.apache.poi.hssf.record.WindowTwoRecord; | |||
import org.apache.poi.ss.util.Region; | |||
import org.apache.poi.util.TempFile; | |||
/** | |||
* Tests HSSFSheet. This test case is very incomplete at the moment. | |||
@@ -54,10 +53,7 @@ public final class TestHSSFSheet extends TestCase { | |||
/** | |||
* Test the gridset field gets set as expected. | |||
*/ | |||
public void testBackupRecord() | |||
throws Exception | |||
{ | |||
public void testBackupRecord() { | |||
HSSFWorkbook wb = new HSSFWorkbook(); | |||
HSSFSheet s = wb.createSheet(); | |||
Sheet sheet = s.getSheet(); | |||
@@ -70,10 +66,7 @@ public final class TestHSSFSheet extends TestCase { | |||
/** | |||
* Test vertically centered output. | |||
*/ | |||
public void testVerticallyCenter() | |||
throws Exception | |||
{ | |||
public void testVerticallyCenter() { | |||
HSSFWorkbook wb = new HSSFWorkbook(); | |||
HSSFSheet s = wb.createSheet(); | |||
Sheet sheet = s.getSheet(); | |||
@@ -90,10 +83,7 @@ public final class TestHSSFSheet extends TestCase { | |||
/** | |||
* Test horizontally centered output. | |||
*/ | |||
public void testHorizontallyCenter() | |||
throws Exception | |||
{ | |||
public void testHorizontallyCenter() { | |||
HSSFWorkbook wb = new HSSFWorkbook(); | |||
HSSFSheet s = wb.createSheet(); | |||
Sheet sheet = s.getSheet(); | |||
@@ -103,16 +93,13 @@ public final class TestHSSFSheet extends TestCase { | |||
assertEquals(false, record.getHCenter()); | |||
s.setHorizontallyCenter(true); | |||
assertEquals(true, record.getHCenter()); | |||
} | |||
/** | |||
* Test WSBboolRecord fields get set in the user model. | |||
*/ | |||
public void testWSBool() | |||
{ | |||
public void testWSBool() { | |||
HSSFWorkbook wb = new HSSFWorkbook(); | |||
HSSFSheet s = wb.createSheet(); | |||
Sheet sheet = s.getSheet(); | |||
@@ -158,9 +145,7 @@ public final class TestHSSFSheet extends TestCase { | |||
assertEquals(true, s.getRowSumsRight()); | |||
} | |||
public void testReadBooleans() | |||
throws Exception | |||
{ | |||
public void testReadBooleans() { | |||
HSSFWorkbook workbook = new HSSFWorkbook(); | |||
HSSFSheet sheet = workbook.createSheet("Test boolean"); | |||
HSSFRow row = sheet.createRow((short) 2); | |||
@@ -168,23 +153,16 @@ public final class TestHSSFSheet extends TestCase { | |||
cell.setCellValue(true); | |||
cell = row.createCell((short) 11); | |||
cell.setCellValue(true); | |||
File tempFile = TempFile.createTempFile("bool", "test.xls"); | |||
FileOutputStream stream = new FileOutputStream(tempFile); | |||
workbook.write(stream); | |||
stream.close(); | |||
workbook = HSSFTestDataSamples.writeOutAndReadBack(workbook); | |||
FileInputStream readStream = new FileInputStream(tempFile); | |||
workbook = new HSSFWorkbook(readStream); | |||
sheet = workbook.getSheetAt(0); | |||
row = sheet.getRow(2); | |||
stream.close(); | |||
tempFile.delete(); | |||
assertNotNull(row); | |||
assertEquals(2, row.getPhysicalNumberOfCells()); | |||
} | |||
public void testRemoveRow() | |||
{ | |||
public void testRemoveRow() { | |||
HSSFWorkbook workbook = new HSSFWorkbook(); | |||
HSSFSheet sheet = workbook.createSheet("Test boolean"); | |||
HSSFRow row = sheet.createRow((short) 2); | |||
@@ -197,8 +175,8 @@ public final class TestHSSFSheet extends TestCase { | |||
HSSFRow row = sheet.createRow(0); | |||
HSSFCell cell = row.createCell((short) 0); | |||
HSSFCell cell2 = row.createCell((short) 1); | |||
cell.setCellValue(new HSSFRichTextString("clone_test")); | |||
cell2.setCellFormula("sin(1)"); | |||
cell.setCellValue(new HSSFRichTextString("clone_test")); | |||
cell2.setCellFormula("sin(1)"); | |||
HSSFSheet clonedSheet = workbook.cloneSheet(0); | |||
HSSFRow clonedRow = clonedSheet.getRow(0); | |||
@@ -234,7 +212,7 @@ public final class TestHSSFSheet extends TestCase { | |||
assertNotNull(workbook.getSheet("Test Clone")); | |||
assertNotNull(workbook.getSheet("Test Clone(1)")); | |||
assertNotNull(workbook.getSheet("Test Clone(2)")); | |||
assertNotNull(workbook.getSheet("Test Clone(2)")); | |||
} | |||
/** | |||
@@ -275,7 +253,7 @@ public final class TestHSSFSheet extends TestCase { | |||
/** | |||
* Setting landscape and portrait stuff on existing sheets | |||
*/ | |||
public void testPrintSetupLandscapeExisting() throws Exception { | |||
public void testPrintSetupLandscapeExisting() { | |||
HSSFWorkbook workbook = openSample("SimpleWithPageBreaks.xls"); | |||
assertEquals(3, workbook.getNumberOfSheets()); | |||
@@ -306,9 +284,7 @@ public final class TestHSSFSheet extends TestCase { | |||
assertEquals(1, sheetLS.getPrintSetup().getCopies()); | |||
// Save and re-load, and check still there | |||
ByteArrayOutputStream baos = new ByteArrayOutputStream(); | |||
workbook.write(baos); | |||
workbook = new HSSFWorkbook(new ByteArrayInputStream(baos.toByteArray())); | |||
workbook = HSSFTestDataSamples.writeOutAndReadBack(workbook); | |||
assertTrue(sheetL.getPrintSetup().getLandscape()); | |||
assertFalse(sheetPM.getPrintSetup().getLandscape()); | |||
@@ -318,7 +294,7 @@ public final class TestHSSFSheet extends TestCase { | |||
assertEquals(1, sheetLS.getPrintSetup().getCopies()); | |||
} | |||
public void testGroupRows() throws Exception { | |||
public void testGroupRows() { | |||
HSSFWorkbook workbook = new HSSFWorkbook(); | |||
HSSFSheet s = workbook.createSheet(); | |||
HSSFRow r1 = s.createRow(0); | |||
@@ -342,11 +318,7 @@ public final class TestHSSFSheet extends TestCase { | |||
assertEquals(0, r5.getOutlineLevel()); | |||
// Save and re-open | |||
ByteArrayOutputStream baos = new ByteArrayOutputStream(); | |||
workbook.write(baos); | |||
workbook = new HSSFWorkbook( | |||
new ByteArrayInputStream(baos.toByteArray()) | |||
); | |||
workbook = HSSFTestDataSamples.writeOutAndReadBack(workbook); | |||
s = workbook.getSheetAt(0); | |||
r1 = s.getRow(0); | |||
@@ -362,7 +334,7 @@ public final class TestHSSFSheet extends TestCase { | |||
assertEquals(0, r5.getOutlineLevel()); | |||
} | |||
public void testGroupRowsExisting() throws Exception { | |||
public void testGroupRowsExisting() { | |||
HSSFWorkbook workbook = openSample("NoGutsRecords.xls"); | |||
HSSFSheet s = workbook.getSheetAt(0); | |||
@@ -391,11 +363,11 @@ public final class TestHSSFSheet extends TestCase { | |||
assertEquals(0, r6.getOutlineLevel()); | |||
// Save and re-open | |||
ByteArrayOutputStream baos = new ByteArrayOutputStream(); | |||
workbook.write(baos); | |||
workbook = new HSSFWorkbook( | |||
new ByteArrayInputStream(baos.toByteArray()) | |||
); | |||
try { | |||
workbook = HSSFTestDataSamples.writeOutAndReadBack(workbook); | |||
} catch (OutOfMemoryError e) { | |||
throw new AssertionFailedError("Identified bug 39903"); | |||
} | |||
s = workbook.getSheetAt(0); | |||
r1 = s.getRow(0); | |||
@@ -413,7 +385,7 @@ public final class TestHSSFSheet extends TestCase { | |||
assertEquals(0, r6.getOutlineLevel()); | |||
} | |||
public void testGetDrawings() throws Exception { | |||
public void testGetDrawings() { | |||
HSSFWorkbook wb1c = openSample("WithChart.xls"); | |||
HSSFWorkbook wb2c = openSample("WithTwoCharts.xls"); | |||
@@ -440,7 +412,7 @@ public final class TestHSSFSheet extends TestCase { | |||
HSSFSheet hssfSheet = workbook.createSheet(); | |||
Sheet sheet = hssfSheet.getSheet(); | |||
ProtectRecord protect = sheet.getProtect(); | |||
assertFalse(protect.getProtect()); | |||
// This will tell us that cloneSheet, and by extension, | |||
@@ -454,12 +426,12 @@ public final class TestHSSFSheet extends TestCase { | |||
public void testProtectSheet() { | |||
short expected = (short)0xfef1; | |||
HSSFWorkbook wb = new HSSFWorkbook(); | |||
HSSFWorkbook wb = new HSSFWorkbook(); | |||
HSSFSheet s = wb.createSheet(); | |||
s.protectSheet("abcdefghij"); | |||
Sheet sheet = s.getSheet(); | |||
ProtectRecord protect = sheet.getProtect(); | |||
PasswordRecord pass = sheet.getPassword(); | |||
ProtectRecord protect = sheet.getProtect(); | |||
PasswordRecord pass = sheet.getPassword(); | |||
assertTrue("protection should be on",protect.getProtect()); | |||
assertTrue("object protection should be on",sheet.isProtected()[1]); | |||
assertTrue("scenario protection should be on",sheet.isProtected()[2]); | |||
@@ -467,9 +439,7 @@ public final class TestHSSFSheet extends TestCase { | |||
} | |||
public void testZoom() | |||
throws Exception | |||
{ | |||
public void testZoom() { | |||
HSSFWorkbook wb = new HSSFWorkbook(); | |||
HSSFSheet sheet = wb.createSheet(); | |||
assertEquals(-1, sheet.getSheet().findFirstRecordLocBySid(SCLRecord.sid)); | |||
@@ -482,7 +452,6 @@ public final class TestHSSFSheet extends TestCase { | |||
int sclLoc = sheet.getSheet().findFirstRecordLocBySid(SCLRecord.sid); | |||
int window2Loc = sheet.getSheet().findFirstRecordLocBySid(WindowTwoRecord.sid); | |||
assertTrue(sclLoc == window2Loc + 1); | |||
} | |||
@@ -493,7 +462,7 @@ public final class TestHSSFSheet extends TestCase { | |||
public void testRemoveMerged() { | |||
HSSFWorkbook wb = new HSSFWorkbook(); | |||
HSSFSheet sheet = wb.createSheet(); | |||
Region region = new Region(0, (short)0, 1, (short)1); | |||
Region region = new Region(0, (short)0, 1, (short)1); | |||
sheet.addMergedRegion(region); | |||
region = new Region(1, (short)0, 2, (short)1); | |||
sheet.addMergedRegion(region); | |||
@@ -522,7 +491,6 @@ public final class TestHSSFSheet extends TestCase { | |||
assertTrue("there isn't more than one merged region in there", 1 <= sheet.getNumMergedRegions()); | |||
region = sheet.getMergedRegionAt(0); | |||
assertEquals("the merged row to doesnt match the one we put in ", 4, region.getRowTo()); | |||
} | |||
public void testShiftMerged() { | |||
@@ -536,33 +504,25 @@ public final class TestHSSFSheet extends TestCase { | |||
cell = row.createCell((short)1); | |||
cell.setCellValue(new HSSFRichTextString("second row, second cell")); | |||
Region region = new Region(1, (short)0, 1, (short)1); | |||
Region region = new Region(1, (short)0, 1, (short)1); | |||
sheet.addMergedRegion(region); | |||
sheet.shiftRows(1, 1, 1); | |||
region = sheet.getMergedRegionAt(0); | |||
assertEquals("Merged region not moved over to row 2", 2, region.getRowFrom()); | |||
} | |||
/** | |||
* Tests the display of gridlines, formulas, and rowcolheadings. | |||
* @author Shawn Laubach (slaubach at apache dot org) | |||
*/ | |||
public void testDisplayOptions() throws Exception { | |||
public void testDisplayOptions() { | |||
HSSFWorkbook wb = new HSSFWorkbook(); | |||
HSSFSheet sheet = wb.createSheet(); | |||
File tempFile = TempFile.createTempFile("display", "test.xls"); | |||
FileOutputStream stream = new FileOutputStream(tempFile); | |||
wb.write(stream); | |||
stream.close(); | |||
FileInputStream readStream = new FileInputStream(tempFile); | |||
wb = new HSSFWorkbook(readStream); | |||
wb = HSSFTestDataSamples.writeOutAndReadBack(wb); | |||
sheet = wb.getSheetAt(0); | |||
readStream.close(); | |||
assertEquals(sheet.isDisplayGridlines(), true); | |||
assertEquals(sheet.isDisplayRowColHeadings(), true); | |||
@@ -572,16 +532,8 @@ public final class TestHSSFSheet extends TestCase { | |||
sheet.setDisplayRowColHeadings(false); | |||
sheet.setDisplayFormulas(true); | |||
tempFile = TempFile.createTempFile("display", "test.xls"); | |||
stream = new FileOutputStream(tempFile); | |||
wb.write(stream); | |||
stream.close(); | |||
readStream = new FileInputStream(tempFile); | |||
wb = new HSSFWorkbook(readStream); | |||
wb = HSSFTestDataSamples.writeOutAndReadBack(wb); | |||
sheet = wb.getSheetAt(0); | |||
readStream.close(); | |||
assertEquals(sheet.isDisplayGridlines(), false); | |||
assertEquals(sheet.isDisplayRowColHeadings(), false); | |||
@@ -593,7 +545,7 @@ public final class TestHSSFSheet extends TestCase { | |||
* Make sure the excel file loads work | |||
* | |||
*/ | |||
public void testPageBreakFiles() throws Exception{ | |||
public void testPageBreakFiles() { | |||
HSSFWorkbook wb = openSample("SimpleWithPageBreaks.xls"); | |||
HSSFSheet sheet = wb.getSheetAt(0); | |||
@@ -611,27 +563,19 @@ public final class TestHSSFSheet extends TestCase { | |||
assertEquals("row breaks number", 2, sheet.getRowBreaks().length); | |||
assertEquals("column breaks number", 2, sheet.getColumnBreaks().length); | |||
File tempFile = TempFile.createTempFile("display", "testPagebreaks.xls"); | |||
FileOutputStream stream = new FileOutputStream(tempFile); | |||
wb.write(stream); | |||
stream.close(); | |||
wb = new HSSFWorkbook(new FileInputStream(tempFile)); | |||
wb = HSSFTestDataSamples.writeOutAndReadBack(wb); | |||
sheet = wb.getSheetAt(0); | |||
assertTrue("No row page break", sheet.isRowBroken(22)); | |||
assertTrue("No column page break", sheet.isColumnBroken((short)4)); | |||
assertEquals("row breaks number", 2, sheet.getRowBreaks().length); | |||
assertEquals("column breaks number", 2, sheet.getColumnBreaks().length); | |||
} | |||
public void testDBCSName () throws Exception { | |||
public void testDBCSName () { | |||
HSSFWorkbook wb = openSample("DBCSSheetName.xls"); | |||
HSSFSheet s= wb.getSheetAt(1); | |||
wb.getSheetAt(1); | |||
assertEquals ("DBCS Sheet Name 2", wb.getSheetName(1),"\u090f\u0915" ); | |||
assertEquals("DBCS Sheet Name 1", wb.getSheetName(0),"\u091c\u093e"); | |||
} | |||
@@ -684,17 +628,15 @@ public final class TestHSSFSheet extends TestCase { | |||
/** | |||
* | |||
*/ | |||
public void testAddEmptyRow() throws Exception { | |||
public void testAddEmptyRow() { | |||
//try to add 5 empty rows to a new sheet | |||
HSSFWorkbook workbook = new HSSFWorkbook(); | |||
HSSFSheet sheet = workbook.createSheet(); | |||
for (int i = 0; i < 5; i++) sheet.createRow(i); | |||
ByteArrayOutputStream out = new ByteArrayOutputStream(); | |||
workbook.write(out); | |||
out.close(); | |||
for (int i = 0; i < 5; i++) { | |||
sheet.createRow(i); | |||
} | |||
workbook = new HSSFWorkbook(new ByteArrayInputStream(out.toByteArray())); | |||
workbook = HSSFTestDataSamples.writeOutAndReadBack(workbook); | |||
//try adding empty rows in an existing worksheet | |||
workbook = openSample("Simple.xls"); | |||
@@ -702,14 +644,10 @@ public final class TestHSSFSheet extends TestCase { | |||
sheet = workbook.getSheetAt(0); | |||
for (int i = 3; i < 10; i++) sheet.createRow(i); | |||
out = new ByteArrayOutputStream(); | |||
workbook.write(out); | |||
out.close(); | |||
workbook = new HSSFWorkbook(new ByteArrayInputStream(out.toByteArray())); | |||
workbook = HSSFTestDataSamples.writeOutAndReadBack(workbook); | |||
} | |||
public void testAutoSizeColumn() throws Exception { | |||
public void testAutoSizeColumn() { | |||
HSSFWorkbook wb = openSample("43902.xls"); | |||
String sheetName = "my sheet"; | |||
HSSFSheet sheet = wb.getSheet(sheetName); | |||
@@ -719,7 +657,7 @@ public final class TestHSSFSheet extends TestCase { | |||
// machines based on the fonts available. | |||
// So, we use ranges, which are pretty large, but | |||
// thankfully don't overlap! | |||
int minWithRow1And2 = 6400; | |||
int minWithRow1And2 = 6400; | |||
int maxWithRow1And2 = 7800; | |||
int minWithRow1Only = 2750; | |||
int maxWithRow1Only = 3300; | |||
@@ -733,13 +671,10 @@ public final class TestHSSFSheet extends TestCase { | |||
//create a region over the 2nd row and auto size the first column | |||
sheet.addMergedRegion(new Region(1,(short)0,1,(short)1)); | |||
sheet.autoSizeColumn((short)0); | |||
ByteArrayOutputStream out = new ByteArrayOutputStream(); | |||
wb.write(out); | |||
out.close(); | |||
HSSFWorkbook wb2 = HSSFTestDataSamples.writeOutAndReadBack(wb); | |||
// check that the autoSized column width has ignored the 2nd row | |||
// check that the autoSized column width has ignored the 2nd row | |||
// because it is included in a merged region (Excel like behavior) | |||
HSSFWorkbook wb2 = new HSSFWorkbook(new ByteArrayInputStream(out.toByteArray())); | |||
HSSFSheet sheet2 = wb2.getSheet(sheetName); | |||
assertTrue(sheet2.getColumnWidth((short)0) >= minWithRow1Only); | |||
assertTrue(sheet2.getColumnWidth((short)0) <= maxWithRow1Only); | |||
@@ -747,10 +682,7 @@ public final class TestHSSFSheet extends TestCase { | |||
// remove the 2nd row merged region and check that the 2nd row value is used to the autoSizeColumn width | |||
sheet2.removeMergedRegion(1); | |||
sheet2.autoSizeColumn((short)0); | |||
out = new ByteArrayOutputStream(); | |||
wb2.write(out); | |||
out.close(); | |||
HSSFWorkbook wb3 = new HSSFWorkbook(new ByteArrayInputStream(out.toByteArray())); | |||
HSSFWorkbook wb3 = HSSFTestDataSamples.writeOutAndReadBack(wb2); | |||
HSSFSheet sheet3 = wb3.getSheet(sheetName); | |||
assertTrue(sheet3.getColumnWidth((short)0) >= minWithRow1And2); | |||
assertTrue(sheet3.getColumnWidth((short)0) <= maxWithRow1And2); | |||
@@ -827,7 +759,7 @@ public final class TestHSSFSheet extends TestCase { | |||
assertTrue(wb3.getSheetAt(3).getForceFormulaRecalculation()); | |||
} | |||
public void testColumnWidth() throws Exception { | |||
public void testColumnWidth() { | |||
//check we can correctly read column widths from a reference workbook | |||
HSSFWorkbook wb = openSample("colwidth.xls"); | |||
@@ -867,11 +799,8 @@ public final class TestHSSFSheet extends TestCase { | |||
} | |||
//serialize and read again | |||
ByteArrayOutputStream out = new ByteArrayOutputStream(); | |||
wb.write(out); | |||
out.close(); | |||
wb = HSSFTestDataSamples.writeOutAndReadBack(wb); | |||
wb = new HSSFWorkbook(new ByteArrayInputStream(out.toByteArray())); | |||
sh = wb.getSheetAt(0); | |||
assertEquals(10, sh.getDefaultColumnWidth()); | |||
//columns A-C have default width |
@@ -20,12 +20,16 @@ package org.apache.poi.hssf.usermodel; | |||
import java.io.File; | |||
import java.io.FileOutputStream; | |||
import java.io.IOException; | |||
import java.util.List; | |||
import junit.framework.AssertionFailedError; | |||
import junit.framework.TestCase; | |||
import org.apache.poi.hssf.HSSFTestDataSamples; | |||
import org.apache.poi.hssf.model.Sheet; | |||
import org.apache.poi.hssf.record.NameRecord; | |||
import org.apache.poi.hssf.record.Record; | |||
import org.apache.poi.hssf.record.RecordInputStream; | |||
import org.apache.poi.util.TempFile; | |||
/** | |||
* | |||
@@ -376,4 +380,49 @@ public final class TestHSSFWorkbook extends TestCase { | |||
assertEquals("active", expectedActive, sheet.isActive()); | |||
assertEquals("selected", expectedSelected, sheet.isSelected()); | |||
} | |||
} | |||
/** | |||
* If Sheet.getSize() returns a different result to Sheet.serialize(), this will cause the BOF | |||
* records to be written with invalid offset indexes. Excel does not like this, and such | |||
* errors are particularly hard to track down. This test ensures that HSSFWorkbook throws | |||
* a specific exception as soon as the situation is detected. See bugzilla 45066 | |||
*/ | |||
public void testSheetSerializeSizeMismatch_bug45066() { | |||
HSSFWorkbook wb = new HSSFWorkbook(); | |||
Sheet sheet = wb.createSheet("Sheet1").getSheet(); | |||
List sheetRecords = sheet.getRecords(); | |||
// one way (of many) to cause the discrepancy is with a badly behaved record: | |||
sheetRecords.add(new BadlyBehavedRecord()); | |||
// There is also much logic inside Sheet that (if buggy) might also cause the discrepancy | |||
try { | |||
wb.getBytes(); | |||
throw new AssertionFailedError("Identified bug 45066 a"); | |||
} catch (IllegalStateException e) { | |||
// Expected badly behaved sheet record to cause exception | |||
assertTrue(e.getMessage().startsWith("Actual serialized sheet size")); | |||
} | |||
} | |||
/** | |||
* result returned by getRecordSize() differs from result returned by serialize() | |||
*/ | |||
private static final class BadlyBehavedRecord extends Record { | |||
public BadlyBehavedRecord() { | |||
// | |||
} | |||
protected void fillFields(RecordInputStream in) { | |||
throw new RuntimeException("Should not be called"); | |||
} | |||
public short getSid() { | |||
return 0x777; | |||
} | |||
public int serialize(int offset, byte[] data) { | |||
return 4; | |||
} | |||
protected void validateSid(short id) { | |||
throw new RuntimeException("Should not be called"); | |||
} | |||
public int getRecordSize() { | |||
return 8; | |||
} | |||
} | |||
} |
@@ -0,0 +1,44 @@ | |||
package org.apache.poi.hssf.usermodel; | |||
import junit.framework.AssertionFailedError; | |||
import junit.framework.TestCase; | |||
import org.apache.poi.hssf.HSSFTestDataSamples; | |||
/** | |||
* Tests for LinkTable | |||
* | |||
* @author Josh Micich | |||
*/ | |||
public final class TestLinkTable extends TestCase { | |||
/** | |||
* The example file attached to bugzilla 45046 is a clear example of Name records being present | |||
* without an External Book (SupBook) record. Excel has no trouble reading this file.<br/> | |||
* TODO get OOO documentation updated to reflect this (that EXTERNALBOOK is optional). | |||
* | |||
* It's not clear what exact steps need to be taken in Excel to create such a workbook | |||
*/ | |||
public void testLinkTableWithoutExternalBookRecord_bug45046() { | |||
HSSFWorkbook wb; | |||
try { | |||
wb = HSSFTestDataSamples.openSampleWorkbook("ex45046-21984.xls"); | |||
} catch (RuntimeException e) { | |||
if ("DEFINEDNAME is part of LinkTable".equals(e.getMessage())) { | |||
throw new AssertionFailedError("Identified bug 45046 b"); | |||
} | |||
throw e; | |||
} | |||
// some other sanity checks | |||
assertEquals(3, wb.getNumberOfSheets()); | |||
String formula = wb.getSheetAt(0).getRow(4).getCell(13).getCellFormula(); | |||
if ("ipcSummenproduktIntern($P5,N$6,$A$9,N$5)".equals(formula)) { | |||
// The reported symptom of this bugzilla is an earlier bug (already fixed) | |||
throw new AssertionFailedError("Identified bug 41726"); | |||
// This is observable in version 3.0 | |||
} | |||
assertEquals("ipcSummenproduktIntern($C5,N$2,$A$9,N$1)", formula); | |||
} | |||
} |
@@ -45,8 +45,8 @@ public final class TestSheetHiding extends TestCase { | |||
*/ | |||
public void testTextSheets() throws Exception { | |||
// Both should have two sheets | |||
assertEquals(2, wbH.sheets.size()); | |||
assertEquals(2, wbU.sheets.size()); | |||
assertEquals(2, wbH.getNumberOfSheets()); | |||
assertEquals(2, wbU.getNumberOfSheets()); | |||
// All sheets should have one row | |||
assertEquals(0, wbH.getSheetAt(0).getLastRowNum()); |