aboutsummaryrefslogtreecommitdiffstats
path: root/src/java/org/apache
diff options
context:
space:
mode:
authorNick Burch <nick@apache.org>2008-09-07 17:34:36 +0000
committerNick Burch <nick@apache.org>2008-09-07 17:34:36 +0000
commit4cfed674685a53464d58de6c4abd0e2ff3b4c5f7 (patch)
tree793068c19f778323c17788fe728fe420ff878ef9 /src/java/org/apache
parente4ff06ec794e82ac0e7c50d71e4fe7dabbfc2ece (diff)
downloadpoi-4cfed674685a53464d58de6c4abd0e2ff3b4c5f7.tar.gz
poi-4cfed674685a53464d58de6c4abd0e2ff3b4c5f7.zip
Merged revisions 638786-638802,638805-638811,638813-638814,638816-639230,639233-639241,639243-639253,639255-639486,639488-639601,639603-639835,639837-639917,639919-640056,640058-640710,640712-641156,641158-641184,641186-641795,641797-641798,641800-641933,641935-641963,641965-641966,641968-641995,641997-642230,642232-642562,642564-642565,642568-642570,642572-642573,642576-642736,642739-642877,642879,642881-642890,642892-642903,642905-642945,642947-643624,643626-643653,643655-643669,643671,643673-643830,643832-643833,643835-644342,644344-644472,644474-644508,644510-645347,645349-645351,645353-645559,645561-645565,645568-645951,645953-646193,646195-646311,646313-646404,646406-646665,646667-646853,646855-646869,646871-647151,647153-647185,647187-647277,647279-647566,647568-647573,647575,647578-647711,647714-647737,647739-647823,647825-648155,648157-648202,648204-648273,648275,648277-648302,648304-648333,648335-648588,648590-648622,648625-648673,648675-649141,649144,649146-649556,649558-649795,649799,649801-649910,649912-649913,649915-650128,650131-650132,650134-650137,650140-650914,650916-651991,651993-652284,652286-652287,652289,652291,652293-652297,652299-652328,652330-652425,652427-652445,652447-652560,652562-652933,652935,652937-652993,652995-653116,653118-653124,653126-653483,653487-653519,653522-653550,653552-653607,653609-653667,653669-653674,653676-653814,653817-653830,653832-653891,653893-653944,653946-654055,654057-654355,654357-654365,654367-654648,654651-655215,655217-655277,655279-655281,655283-655911,655913-656212,656214,656216-656251,656253-656698,656700-656756,656758-656892,656894-657135,657137-657165,657168-657179,657181-657354,657356-657357,657359-657701,657703-657874,657876-658032,658034-658284,658286,658288-658301,658303-658307,658309-658321,658323-658335,658337-658348,658351,658353-658832,658834-658983,658985,658987-659066,659068-659402,659404-659428,659430-659451,659453-659454,659456-659461,659463-659477,659479-659524,659526-659571,659574,659576-660255,660257-660262,660264-660279,660281-660343,660345-660473,660475-660827,660829-660833,660835-660888,660890-663321,663323-663435,663437-663764,663766-663854,663856-664219,664221-664489,664494-664514,664516-668013,668015-668142,668144-668152,668154,668156-668256,668258,668260-669139,669141-669455,669457-669657,669659-669808,669810-670189,670191-671321,671323-672229,672231-672549,672551-672552,672554-672561,672563-672566,672568,672571-673049,673051-673852,673854-673862,673864-673986,673988-673996,673998-674347,674349-674890,674892-674910,674912-674936,674938-674952,674954-675078,675080-675085,675087-675217,675219-675660,675662-675670,675672-675716,675718-675726,675728-675733,675735-675775,675777-675782,675784,675786-675791,675794-675852,675854-676200,676202,676204,676206-676220,676222-676309,676311-676456,676458-676994,676996-677027,677030-677040,677042-677056,677058-677375,677377-677968,677970-677971,677973,677975-677994,677996-678286,678288-678538,678540-680393,680395-680469,680471-680529,680531-680852,680854-681529,681531-681571,681573-682224,682226,682228,682231-682281,682283-682335,682337-682507,682509,682512-682517,682519-682532,682534-682619,682622-682777,682779-682998,683000-683019,683021-683022,683024-683080,683082-683092,683094-683095,683097-683127,683129-683131,683133-683166,683168-683698,683700-683705,683707-683757,683759-683787,683789-683870,683872-683879,683881-683900,683902-684066,684068-684074,684076-684222,684224-684254,684257-684281,684283-684286,684288-684292,684294-684298,684300-684301,684303-684308,684310-684317,684320,684323-684335,684337-684348,684350-684354,684356-684361,684363-684369,684371-684453,684455-684883,684885-684937,684940-684958,684960-684970,684972-684985,684987-685053,685055-685063,685065-685259,685261-685262,685264-685266,685268-685282,685285-686035,686037-686045,686047-686052,686054-686206,686208-686215,686217-686277,686279-686289,686291-686620,686622-686623,686626-686627,686629-686639,686641-686843,686845-686976,686978-687402,687404-687422,687424-687428,687430-687442,687444-688425,688427-688641,688643-688649,688651-688654,688656-688824,688826-688909,688911-689543,689545-689558,689560-689635,689637-689703,689705-689715,689717-689718,689720,689722-689972,689974-690090,690092-690093,690095-690111,690113-690258,690260-690261,690263-690403,690405-690410,690412-690460,690462-690516,690518-690533,690535,690537-690625,690627-690635,690637-690720,690722-690725,690727-690728,690730-691382 via svnmerge from
https://svn.apache.org/repos/asf/poi/trunk ........ r690739 | nick | 2008-08-31 18:24:10 +0100 (Sun, 31 Aug 2008) | 1 line HPBF docs update ........ r690761 | josh | 2008-08-31 20:08:36 +0100 (Sun, 31 Aug 2008) | 1 line removed AreaEval.getValues (initial work for bug 45358) ........ r690772 | josh | 2008-08-31 20:44:11 +0100 (Sun, 31 Aug 2008) | 1 line Partial fix for bug 45358 - parsing area refs with rows above 32767 ........ r690825 | josh | 2008-09-01 00:59:26 +0100 (Mon, 01 Sep 2008) | 1 line Improving AreaI interface and AreaPtg hierarchy ........ r690835 | josh | 2008-09-01 02:48:45 +0100 (Mon, 01 Sep 2008) | 1 line Converted AreEval and RefEval to be lazy (part of fix for bug 45358) ........ r690836 | josh | 2008-09-01 03:26:33 +0100 (Mon, 01 Sep 2008) | 1 line Fixed IF() to handle different types for the first arg ........ r690837 | josh | 2008-09-01 03:34:05 +0100 (Mon, 01 Sep 2008) | 1 line Update status for bug 45358 (fixed with r690772, r690835 and r690836) ........ r691017 | nick | 2008-09-01 17:51:09 +0100 (Mon, 01 Sep 2008) | 1 line DV related fixes from Pierre Lavignotte ........ r691180 | yegor | 2008-09-02 10:59:53 +0100 (Tue, 02 Sep 2008) | 1 line improved handling of StyleTextPropAtom bit masks, added more read-write roundtrip tests ........ r691182 | yegor | 2008-09-02 11:03:11 +0100 (Tue, 02 Sep 2008) | 1 line continue making progress with hslf hyperlinks ........ git-svn-id: https://svn.apache.org/repos/asf/poi/branches/ooxml@692907 13f79535-47bb-0310-9956-ffa450edef68
Diffstat (limited to 'src/java/org/apache')
-rw-r--r--src/java/org/apache/poi/hssf/record/NameRecord.java8
-rw-r--r--src/java/org/apache/poi/hssf/record/formula/Area2DPtgBase.java59
-rw-r--r--src/java/org/apache/poi/hssf/record/formula/Area3DPtg.java244
-rw-r--r--src/java/org/apache/poi/hssf/record/formula/AreaI.java92
-rw-r--r--src/java/org/apache/poi/hssf/record/formula/AreaNPtg.java2
-rwxr-xr-xsrc/java/org/apache/poi/hssf/record/formula/AreaPtg.java18
-rw-r--r--src/java/org/apache/poi/hssf/record/formula/AreaPtgBase.java61
-rw-r--r--src/java/org/apache/poi/hssf/record/formula/RefPtgBase.java8
-rw-r--r--src/java/org/apache/poi/hssf/record/formula/eval/Area2DEval.java32
-rw-r--r--src/java/org/apache/poi/hssf/record/formula/eval/Area3DEval.java39
-rw-r--r--src/java/org/apache/poi/hssf/record/formula/eval/AreaEval.java13
-rw-r--r--src/java/org/apache/poi/hssf/record/formula/eval/AreaEvalBase.java38
-rw-r--r--src/java/org/apache/poi/hssf/record/formula/eval/FunctionEval.java3
-rw-r--r--src/java/org/apache/poi/hssf/record/formula/eval/LazyAreaEval.java65
-rw-r--r--src/java/org/apache/poi/hssf/record/formula/eval/LazyRefEval.java52
-rw-r--r--src/java/org/apache/poi/hssf/record/formula/eval/NumberEval.java8
-rw-r--r--src/java/org/apache/poi/hssf/record/formula/eval/Ref2DEval.java3
-rw-r--r--src/java/org/apache/poi/hssf/record/formula/eval/Ref3DEval.java53
-rw-r--r--src/java/org/apache/poi/hssf/record/formula/eval/RefEval.java50
-rw-r--r--src/java/org/apache/poi/hssf/record/formula/eval/RefEvalBase.java18
-rw-r--r--src/java/org/apache/poi/hssf/record/formula/functions/CountUtils.java9
-rw-r--r--src/java/org/apache/poi/hssf/record/formula/functions/If.java87
-rw-r--r--src/java/org/apache/poi/hssf/record/formula/functions/Index.java102
-rw-r--r--src/java/org/apache/poi/hssf/record/formula/functions/LookupUtils.java10
-rw-r--r--src/java/org/apache/poi/hssf/record/formula/functions/MathX.java79
-rw-r--r--src/java/org/apache/poi/hssf/record/formula/functions/MultiOperandNumericFunction.java50
-rw-r--r--src/java/org/apache/poi/hssf/record/formula/functions/Offset.java102
-rw-r--r--src/java/org/apache/poi/hssf/record/formula/functions/Sumx2my2.java45
-rw-r--r--src/java/org/apache/poi/hssf/record/formula/functions/Sumx2py2.java45
-rw-r--r--src/java/org/apache/poi/hssf/record/formula/functions/Sumxmy2.java45
-rw-r--r--src/java/org/apache/poi/hssf/record/formula/functions/XYNumericFunction.java324
-rw-r--r--src/java/org/apache/poi/hssf/usermodel/HSSFFormulaEvaluator.java10
-rw-r--r--src/java/org/apache/poi/hssf/usermodel/HSSFSheet.java28
-rw-r--r--src/java/org/apache/poi/hssf/usermodel/HSSFWorkbook.java32
-rw-r--r--src/java/org/apache/poi/hssf/util/AreaReference.java280
-rw-r--r--src/java/org/apache/poi/ss/usermodel/FormulaEvaluator.java411
-rw-r--r--src/java/org/apache/poi/ss/util/AreaReference.java296
37 files changed, 1210 insertions, 1611 deletions
diff --git a/src/java/org/apache/poi/hssf/record/NameRecord.java b/src/java/org/apache/poi/hssf/record/NameRecord.java
index 6c6c53a92b..71f3bf6fb7 100644
--- a/src/java/org/apache/poi/hssf/record/NameRecord.java
+++ b/src/java/org/apache/poi/hssf/record/NameRecord.java
@@ -27,8 +27,8 @@ import org.apache.poi.hssf.record.formula.Ptg;
import org.apache.poi.hssf.record.formula.Ref3DPtg;
import org.apache.poi.hssf.record.formula.UnionPtg;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
-import org.apache.poi.hssf.util.AreaReference;
import org.apache.poi.hssf.util.RangeAddress;
+import org.apache.poi.ss.util.AreaReference;
import org.apache.poi.util.HexDump;
import org.apache.poi.util.LittleEndian;
import org.apache.poi.util.StringUtil;
@@ -626,7 +626,7 @@ public final class NameRecord extends Record {
}
private Ptg createNewPtg(){
- Ptg ptg = new Area3DPtg();
+ Ptg ptg = new Area3DPtg("A1", 0); // TODO - change to not be partially initialised
field_13_name_definition.push(ptg);
return ptg;
@@ -673,9 +673,7 @@ public final class NameRecord extends Record {
// Add the area reference(s)
for(int i=0; i<refs.length; i++) {
- ptg = new Area3DPtg();
- ((Area3DPtg) ptg).setExternSheetIndex(externSheetIndex);
- ((Area3DPtg) ptg).setArea(refs[i].formatAsString());
+ ptg = new Area3DPtg(refs[i].formatAsString(), externSheetIndex);
field_13_name_definition.push(ptg);
this.setDefinitionTextLength( (short)(getDefinitionLength() + ptg.getSize()) );
}
diff --git a/src/java/org/apache/poi/hssf/record/formula/Area2DPtgBase.java b/src/java/org/apache/poi/hssf/record/formula/Area2DPtgBase.java
new file mode 100644
index 0000000000..2193854f47
--- /dev/null
+++ b/src/java/org/apache/poi/hssf/record/formula/Area2DPtgBase.java
@@ -0,0 +1,59 @@
+/* ====================================================================
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+==================================================================== */
+
+package org.apache.poi.hssf.record.formula;
+
+import org.apache.poi.hssf.record.RecordInputStream;
+import org.apache.poi.hssf.usermodel.HSSFWorkbook;
+import org.apache.poi.util.LittleEndian;
+
+/**
+ * Common superclass of 2-D area refs
+ */
+public abstract class Area2DPtgBase extends AreaPtgBase {
+ private final static int SIZE = 9;
+
+ protected Area2DPtgBase(int firstRow, int lastRow, int firstColumn, int lastColumn, boolean firstRowRelative, boolean lastRowRelative, boolean firstColRelative, boolean lastColRelative) {
+ super(firstRow, lastRow, firstColumn, lastColumn, firstRowRelative, lastRowRelative, firstColRelative, lastColRelative);
+ }
+ protected Area2DPtgBase(RecordInputStream in) {
+ readCoordinates(in);
+ }
+ protected abstract byte getSid();
+
+ public final void writeBytes(byte [] array, int offset) {
+ LittleEndian.putByte(array, offset+0, getSid() + getPtgClass());
+ writeCoordinates(array, offset+1);
+ }
+ public Area2DPtgBase(String arearef) {
+ super(arearef);
+ }
+ public final int getSize() {
+ return SIZE;
+ }
+ public final String toFormulaString(HSSFWorkbook book) {
+ return formatReferenceAsString();
+ }
+ public final String toString() {
+ StringBuffer sb = new StringBuffer();
+ sb.append(getClass().getName());
+ sb.append(" [");
+ sb.append(formatReferenceAsString());
+ sb.append("]");
+ return sb.toString();
+ }
+}
diff --git a/src/java/org/apache/poi/hssf/record/formula/Area3DPtg.java b/src/java/org/apache/poi/hssf/record/formula/Area3DPtg.java
index 3c9404ac39..ba207ab5c6 100644
--- a/src/java/org/apache/poi/hssf/record/formula/Area3DPtg.java
+++ b/src/java/org/apache/poi/hssf/record/formula/Area3DPtg.java
@@ -18,11 +18,9 @@
package org.apache.poi.hssf.record.formula;
import org.apache.poi.ss.usermodel.Workbook;
-import org.apache.poi.ss.util.CellReference;
-import org.apache.poi.hssf.util.AreaReference;
import org.apache.poi.hssf.record.RecordInputStream;
-import org.apache.poi.util.BitField;
-import org.apache.poi.util.BitFieldFactory;
+import org.apache.poi.ss.util.AreaReference;
+import org.apache.poi.ss.util.CellReference;
import org.apache.poi.util.LittleEndian;
/**
@@ -34,238 +32,63 @@ import org.apache.poi.util.LittleEndian;
* @author Jason Height (jheight at chariot dot net dot au)
* @version 1.0-pre
*/
-public final class Area3DPtg extends OperandPtg implements AreaI {
+public final class Area3DPtg extends AreaPtgBase {
public final static byte sid = 0x3b;
private final static int SIZE = 11; // 10 + 1 for Ptg
- private static final BitField rowRelative = BitFieldFactory.getInstance(0x8000);
- private static final BitField colRelative = BitFieldFactory.getInstance(0x4000);
-
- private short field_1_index_extern_sheet;
- private int field_2_first_row;
- private int field_3_last_row;
- private int field_4_first_column;
- private int field_5_last_column;
+ private int field_1_index_extern_sheet;
- /** Creates new AreaPtg */
- public Area3DPtg()
- {
- }
-
- public Area3DPtg( String arearef, short externIdx )
- {
- setArea(arearef);
+ public Area3DPtg( String arearef, int externIdx ) {
+ super(arearef);
setExternSheetIndex( externIdx );
-
}
- public Area3DPtg(RecordInputStream in)
- {
+ public Area3DPtg(RecordInputStream in) {
field_1_index_extern_sheet = in.readShort();
- field_2_first_row = in.readUShort();
- field_3_last_row = in.readUShort();
- field_4_first_column = in.readUShort();
- field_5_last_column = in.readUShort();
+ readCoordinates(in);
}
- public Area3DPtg(short firstRow, short lastRow, short firstColumn, short lastColumn,
+ public Area3DPtg(int firstRow, int lastRow, int firstColumn, int lastColumn,
boolean firstRowRelative, boolean lastRowRelative, boolean firstColRelative, boolean lastColRelative,
- short externalSheetIndex) {
- setFirstRow(firstRow);
- setLastRow(lastRow);
- setFirstColumn(firstColumn);
- setLastColumn(lastColumn);
- setFirstRowRelative(firstRowRelative);
- setLastRowRelative(lastRowRelative);
- setFirstColRelative(firstColRelative);
- setLastColRelative(lastColRelative);
- setExternSheetIndex(externalSheetIndex);
+ int externalSheetIndex) {
+ super(firstRow, lastRow, firstColumn, lastColumn, firstRowRelative, lastRowRelative, firstColRelative, lastColRelative);
+ setExternSheetIndex(externalSheetIndex);
}
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(formatReferenceAsString());
sb.append("]");
return sb.toString();
}
- public void writeBytes( byte[] array, int offset )
- {
- array[0 + offset] = (byte) ( sid + getPtgClass() );
- LittleEndian.putShort( array, 1 + offset, getExternSheetIndex() );
- LittleEndian.putShort( array, 3 + offset, (short)getFirstRow() );
- LittleEndian.putShort( array, 5 + offset, (short)getLastRow() );
- LittleEndian.putShort( array, 7 + offset, (short)getFirstColumnRaw() );
- LittleEndian.putShort( array, 9 + offset, (short)getLastColumnRaw() );
+ public void writeBytes(byte[] array, int offset) {
+ LittleEndian.putByte(array, offset + 0, sid + getPtgClass());
+ LittleEndian.putUShort(array, 1 + offset, field_1_index_extern_sheet);
+ writeCoordinates(array, offset+3);
}
- public int getSize()
- {
+ public int getSize() {
return SIZE;
}
- public short getExternSheetIndex()
- {
- return field_1_index_extern_sheet;
+ public short getExternSheetIndex() {
+ return (short)field_1_index_extern_sheet;
}
- public void setExternSheetIndex( short index )
- {
+ public void setExternSheetIndex(int index) {
field_1_index_extern_sheet = index;
}
- public int getFirstRow()
- {
- return field_2_first_row;
- }
-
- public void setFirstRow( int row )
- {
- field_2_first_row = row;
- }
-
- public int getLastRow()
- {
- return field_3_last_row;
- }
-
- public void setLastRow( int row )
- {
- field_3_last_row = row;
- }
-
- public int getFirstColumn()
- {
- return field_4_first_column & 0xFF;
- }
-
- public int getFirstColumnRaw()
- {
- return field_4_first_column;
- }
-
- public boolean isFirstRowRelative()
- {
- return rowRelative.isSet( field_4_first_column );
- }
-
- public boolean isFirstColRelative()
- {
- return colRelative.isSet( field_4_first_column );
- }
-
- public void setFirstColumn( short column )
- {
- field_4_first_column &= 0xFF00;
- field_4_first_column |= column & 0xFF;
- }
-
- public void setFirstColumnRaw( short column )
- {
- field_4_first_column = column;
- }
-
- public int getLastColumn()
- {
- return field_5_last_column & 0xFF;
- }
-
- public int getLastColumnRaw()
- {
- return field_5_last_column;
- }
-
- public boolean isLastRowRelative()
- {
- return rowRelative.isSet( field_5_last_column );
- }
-
- public boolean isLastColRelative()
- {
- return colRelative.isSet( field_5_last_column );
- }
-
- public void setLastColumn( short column )
- {
- field_5_last_column &= 0xFF00;
- field_5_last_column |= column & 0xFF;
- }
-
- public void setLastColumnRaw( short column )
- {
- field_5_last_column = column;
- }
-
- /**
- * sets the first row to relative or not
- * @param rel FIXME: Document this!
- */
- public void setFirstRowRelative( boolean rel )
- {
- field_4_first_column = rowRelative.setBoolean( field_4_first_column, rel );
- }
-
- /**
- * set whether the first column is relative
- */
- public void setFirstColRelative( boolean rel )
- {
- field_4_first_column = colRelative.setBoolean( field_4_first_column, rel );
- }
-
- /**
- * set whether the last row is relative or not
- * @param rel FIXME: Document this!
- */
- public void setLastRowRelative( boolean rel )
- {
- field_5_last_column = rowRelative.setBoolean( field_5_last_column, rel );
- }
-
- /**
- * set whether the last column should be relative or not
- */
- public void setLastColRelative( boolean rel )
- {
- field_5_last_column = colRelative.setBoolean( field_5_last_column, rel );
- }
-
-
- /*public String getArea(){
- RangeAddress ra = new RangeAddress( getFirstColumn(),getFirstRow() + 1, getLastColumn(), getLastRow() + 1);
- String result = ra.getAddress();
-
- return result;
- }*/
-
- public void setArea( String ref )
- {
- AreaReference ar = new AreaReference( ref );
-
- CellReference frstCell = ar.getFirstCell();
- CellReference lastCell = ar.getLastCell();
-
- setFirstRow( (short) frstCell.getRow() );
- setFirstColumn( (short) frstCell.getCol() );
- setLastRow( (short) lastCell.getRow() );
- setLastColumn( (short) lastCell.getCol() );
- setFirstColRelative( !frstCell.isColAbsolute() );
- setLastColRelative( !lastCell.isColAbsolute() );
- setFirstRowRelative( !frstCell.isRowAbsolute() );
- setLastRowRelative( !lastCell.isRowAbsolute() );
- }
-
/**
* @return text representation of this area reference that can be used in text
* formulas. The sheet name will get properly delimited if required.
*/
- public String toFormulaString(Workbook book)
- {
+ public String toFormulaString(Workbook book) {
// First do the sheet name
StringBuffer retval = new StringBuffer();
String sheetName = Ref3DPtg.getSheetName(book, field_1_index_extern_sheet);
@@ -282,29 +105,8 @@ public final class Area3DPtg extends OperandPtg implements AreaI {
}
// Now the normal area bit
- retval.append(AreaReference.formatAsString(this));
+ retval.append(formatReferenceAsString());
- // All done
return retval.toString();
}
-
- public byte getDefaultOperandClass() {
- return Ptg.CLASS_REF;
- }
- // TODO - one junit relies on this. remove
- public boolean equals( Object o )
- {
- if ( this == o ) return true;
- if ( !( o instanceof Area3DPtg ) ) return false;
-
- final Area3DPtg area3DPtg = (Area3DPtg) o;
-
- if ( field_1_index_extern_sheet != area3DPtg.field_1_index_extern_sheet ) return false;
- if ( field_2_first_row != area3DPtg.field_2_first_row ) return false;
- if ( field_3_last_row != area3DPtg.field_3_last_row ) return false;
- if ( field_4_first_column != area3DPtg.field_4_first_column ) return false;
- if ( field_5_last_column != area3DPtg.field_5_last_column ) return false;
-
- return true;
- }
}
diff --git a/src/java/org/apache/poi/hssf/record/formula/AreaI.java b/src/java/org/apache/poi/hssf/record/formula/AreaI.java
index 5a0a21e861..477d32f677 100644
--- a/src/java/org/apache/poi/hssf/record/formula/AreaI.java
+++ b/src/java/org/apache/poi/hssf/record/formula/AreaI.java
@@ -14,47 +14,63 @@
See the License for the specific language governing permissions and
limitations under the License.
==================================================================== */
+
package org.apache.poi.hssf.record.formula;
/**
- * Common interface for AreaPtg and Area3DPtg, and their
- * child classes.
+ * Common interface for AreaPtg and Area3DPtg, and their child classes.
*/
public interface AreaI {
- /**
- * @return the first row in the area
- */
- public int getFirstRow();
-
- /**
- * @return last row in the range (x2 in x1,y1-x2,y2)
- */
- public int getLastRow();
-
- /**
- * @return the first column number in the area.
- */
- public int getFirstColumn();
-
- /**
- * @return lastcolumn in the area
- */
- public int getLastColumn();
-
- /**
- * @return isrelative first column to relative or not
- */
- public boolean isFirstColRelative();
- /**
- * @return lastcol relative or not
- */
- public boolean isLastColRelative();
- /**
- * @return whether or not the first row is a relative reference or not.
- */
- public boolean isFirstRowRelative();
- /**
- * @return last row relative or not
- */
- public boolean isLastRowRelative();
+ /**
+ * @return the first row in the area
+ */
+ public int getFirstRow();
+
+ /**
+ * @return last row in the range (x2 in x1,y1-x2,y2)
+ */
+ public int getLastRow();
+
+ /**
+ * @return the first column number in the area.
+ */
+ public int getFirstColumn();
+
+ /**
+ * @return lastcolumn in the area
+ */
+ public int getLastColumn();
+
+ class OffsetArea implements AreaI {
+
+ private final int _firstColumn;
+ private final int _firstRow;
+ private final int _lastColumn;
+ private final int _lastRow;
+
+ public OffsetArea(int baseRow, int baseColumn, int relFirstRowIx, int relLastRowIx,
+ int relFirstColIx, int relLastColIx) {
+ _firstRow = baseRow + relFirstRowIx;
+ _lastRow = baseRow + relLastRowIx;
+ _firstColumn = baseColumn + relFirstColIx;
+ _lastColumn = baseColumn + relLastColIx;
+ }
+
+ public int getFirstColumn() {
+ return _firstColumn;
+ }
+
+ public int getFirstRow() {
+ return _firstRow;
+ }
+
+ public int getLastColumn() {
+ return _lastColumn;
+ }
+
+ public int getLastRow() {
+ return _lastRow;
+ }
+ }
+
} \ No newline at end of file
diff --git a/src/java/org/apache/poi/hssf/record/formula/AreaNPtg.java b/src/java/org/apache/poi/hssf/record/formula/AreaNPtg.java
index bf013838b2..fc391b801d 100644
--- a/src/java/org/apache/poi/hssf/record/formula/AreaNPtg.java
+++ b/src/java/org/apache/poi/hssf/record/formula/AreaNPtg.java
@@ -23,7 +23,7 @@ import org.apache.poi.hssf.record.RecordInputStream;
* Specifies a rectangular area of cells A1:A4 for instance.
* @author Jason Height (jheight at chariot dot net dot au)
*/
-public final class AreaNPtg extends AreaPtgBase {
+public final class AreaNPtg extends Area2DPtgBase {
public final static short sid = 0x2D;
public AreaNPtg(RecordInputStream in) {
diff --git a/src/java/org/apache/poi/hssf/record/formula/AreaPtg.java b/src/java/org/apache/poi/hssf/record/formula/AreaPtg.java
index 0839e5570a..77e9fa0b5e 100755
--- a/src/java/org/apache/poi/hssf/record/formula/AreaPtg.java
+++ b/src/java/org/apache/poi/hssf/record/formula/AreaPtg.java
@@ -23,16 +23,16 @@ import org.apache.poi.hssf.record.RecordInputStream;
* Specifies a rectangular area of cells A1:A4 for instance.
* @author Jason Height (jheight at chariot dot net dot au)
*/
-public final class AreaPtg extends AreaPtgBase {
- public final static short sid = 0x25;
+public final class AreaPtg extends Area2DPtgBase {
+ public final static short sid = 0x25;
- public AreaPtg(int firstRow, int lastRow, int firstColumn, int lastColumn, boolean firstRowRelative, boolean lastRowRelative, boolean firstColRelative, boolean lastColRelative) {
- super(firstRow, lastRow, firstColumn, lastColumn, firstRowRelative, lastRowRelative, firstColRelative, lastColRelative);
- }
- public AreaPtg(RecordInputStream in) {
- super(in);
- }
- public AreaPtg(String arearef) {
+ public AreaPtg(int firstRow, int lastRow, int firstColumn, int lastColumn, boolean firstRowRelative, boolean lastRowRelative, boolean firstColRelative, boolean lastColRelative) {
+ super(firstRow, lastRow, firstColumn, lastColumn, firstRowRelative, lastRowRelative, firstColRelative, lastColRelative);
+ }
+ public AreaPtg(RecordInputStream in) {
+ super(in);
+ }
+ public AreaPtg(String arearef) {
super(arearef);
}
protected byte getSid() {
diff --git a/src/java/org/apache/poi/hssf/record/formula/AreaPtgBase.java b/src/java/org/apache/poi/hssf/record/formula/AreaPtgBase.java
index 9ac406b319..cf3d82cacf 100644
--- a/src/java/org/apache/poi/hssf/record/formula/AreaPtgBase.java
+++ b/src/java/org/apache/poi/hssf/record/formula/AreaPtgBase.java
@@ -23,7 +23,7 @@ import org.apache.poi.util.BitFieldFactory;
import org.apache.poi.ss.util.CellReference;
import org.apache.poi.ss.usermodel.Workbook;
-import org.apache.poi.hssf.util.AreaReference;
+import org.apache.poi.ss.util.AreaReference;
import org.apache.poi.hssf.record.RecordInputStream;
/**
@@ -37,11 +37,9 @@ public abstract class AreaPtgBase extends OperandPtg implements AreaI {
* see similar comment in ReferencePtg
*/
protected final RuntimeException notImplemented() {
- return new RuntimeException("Coding Error: This method should never be called. This ptg should be converted");
+ return new RuntimeException("Coding Error: This method should never be called. This ptg should be converted");
}
- public final static short sid = 0x25;
- private final static int SIZE = 9;
/** zero based, unsigned 16 bit */
private int field_1_first_row;
/** zero based, unsigned 16 bit */
@@ -55,6 +53,10 @@ public abstract class AreaPtgBase extends OperandPtg implements AreaI {
private final static BitField colRelative = BitFieldFactory.getInstance(0x4000);
private final static BitField columnMask = BitFieldFactory.getInstance(0x3FFF);
+ protected AreaPtgBase() {
+ // do nothing
+ }
+
protected AreaPtgBase(String arearef) {
AreaReference ar = new AreaReference(arearef);
CellReference firstCell = ar.getFirstCell();
@@ -97,35 +99,17 @@ public abstract class AreaPtgBase extends OperandPtg implements AreaI {
}
}
- protected AreaPtgBase(RecordInputStream in)
- {
- field_1_first_row = in.readUShort();
- field_2_last_row = in.readUShort();
+ protected final void readCoordinates(RecordInputStream in) {
+ field_1_first_row = in.readUShort();
+ field_2_last_row = in.readUShort();
field_3_first_column = in.readUShort();
- field_4_last_column = in.readUShort();
- }
-
- public final String toString() {
- StringBuffer sb = new StringBuffer();
- sb.append(getClass().getName());
- sb.append(" [");
- sb.append(AreaReference.formatAsString(this));
- sb.append("]");
- return sb.toString();
+ field_4_last_column = in.readUShort();
}
- protected abstract byte getSid();
-
- public final void writeBytes(byte [] array, int offset) {
- array[offset] = (byte) (getSid() + getPtgClass());
- LittleEndian.putShort(array,offset+1,(short)field_1_first_row);
- LittleEndian.putShort(array,offset+3,(short)field_2_last_row);
- LittleEndian.putShort(array,offset+5,(short)field_3_first_column);
- LittleEndian.putShort(array,offset+7,(short)field_4_last_column);
- }
-
-
- public final int getSize() {
- return SIZE;
+ protected final void writeCoordinates(byte[] array, int offset) {
+ LittleEndian.putUShort(array, offset + 0, field_1_first_row);
+ LittleEndian.putUShort(array, offset + 2, field_2_last_row);
+ LittleEndian.putUShort(array, offset + 4, field_3_first_column);
+ LittleEndian.putUShort(array, offset + 6, field_4_last_column);
}
/**
@@ -207,7 +191,7 @@ public abstract class AreaPtgBase extends OperandPtg implements AreaI {
*/
public final void setFirstColumn(int colIx) {
checkColumnBounds(colIx);
- field_3_first_column=columnMask.setValue(field_3_first_column, colIx);
+ field_3_first_column=columnMask.setValue(field_3_first_column, colIx);
}
/**
@@ -266,7 +250,7 @@ public abstract class AreaPtgBase extends OperandPtg implements AreaI {
*/
public final void setLastColumn(int colIx) {
checkColumnBounds(colIx);
- field_4_last_column=columnMask.setValue(field_4_last_column, colIx);
+ field_4_last_column=columnMask.setValue(field_4_last_column, colIx);
}
/**
@@ -275,9 +259,18 @@ public abstract class AreaPtgBase extends OperandPtg implements AreaI {
public final void setLastColumnRaw(short column) {
field_4_last_column = column;
}
+ protected final String formatReferenceAsString() {
+ CellReference topLeft = new CellReference(getFirstRow(),getFirstColumn(),!isFirstRowRelative(),!isFirstColRelative());
+ CellReference botRight = new CellReference(getLastRow(),getLastColumn(),!isLastRowRelative(),!isLastColRelative());
+
+ if(AreaReference.isWholeColumnReference(topLeft, botRight)) {
+ return (new AreaReference(topLeft, botRight)).formatAsString();
+ }
+ return topLeft.formatAsString() + ":" + botRight.formatAsString();
+ }
public String toFormulaString(Workbook book) {
- return AreaReference.formatAsString(this);
+ return formatReferenceAsString();
}
public byte getDefaultOperandClass() {
diff --git a/src/java/org/apache/poi/hssf/record/formula/RefPtgBase.java b/src/java/org/apache/poi/hssf/record/formula/RefPtgBase.java
index 87207f6a07..33dff9ec04 100644
--- a/src/java/org/apache/poi/hssf/record/formula/RefPtgBase.java
+++ b/src/java/org/apache/poi/hssf/record/formula/RefPtgBase.java
@@ -131,14 +131,6 @@ public abstract class RefPtgBase extends OperandPtg {
field_2_col=colRelative.setBoolean(field_2_col,rel);
}
- public final void setColumnRawX(int col) { // TODO
- field_2_col = col;
- }
-
- public int getColumnRawX() { // TODO
- return field_2_col;
- }
-
public final void setColumn(int col) {
if(col < 0 || col >= 0x100) {
throw new IllegalArgumentException("Specified colIx (" + col + ") is out of range");
diff --git a/src/java/org/apache/poi/hssf/record/formula/eval/Area2DEval.java b/src/java/org/apache/poi/hssf/record/formula/eval/Area2DEval.java
deleted file mode 100644
index 5ae98b39fe..0000000000
--- a/src/java/org/apache/poi/hssf/record/formula/eval/Area2DEval.java
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
-* Licensed to the Apache Software Foundation (ASF) under one or more
-* contributor license agreements. See the NOTICE file distributed with
-* this work for additional information regarding copyright ownership.
-* The ASF licenses this file to You under the Apache License, Version 2.0
-* (the "License"); you may not use this file except in compliance with
-* the License. You may obtain a copy of the License at
-*
-* http://www.apache.org/licenses/LICENSE-2.0
-*
-* Unless required by applicable law or agreed to in writing, software
-* distributed under the License is distributed on an "AS IS" BASIS,
-* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-* See the License for the specific language governing permissions and
-* limitations under the License.
-*/
-
-package org.apache.poi.hssf.record.formula.eval;
-
-import org.apache.poi.hssf.record.formula.AreaPtg;
-import org.apache.poi.hssf.record.formula.Ptg;
-
-/**
- * @author Amol S. Deshmukh &lt; amolweb at ya hoo dot com &gt;
- *
- */
-public final class Area2DEval extends AreaEvalBase {
-
- public Area2DEval(Ptg ptg, ValueEval[] values) {
- super((AreaPtg) ptg, values);
- }
-} \ No newline at end of file
diff --git a/src/java/org/apache/poi/hssf/record/formula/eval/Area3DEval.java b/src/java/org/apache/poi/hssf/record/formula/eval/Area3DEval.java
deleted file mode 100644
index 89209e21b6..0000000000
--- a/src/java/org/apache/poi/hssf/record/formula/eval/Area3DEval.java
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
-* Licensed to the Apache Software Foundation (ASF) under one or more
-* contributor license agreements. See the NOTICE file distributed with
-* this work for additional information regarding copyright ownership.
-* The ASF licenses this file to You under the Apache License, Version 2.0
-* (the "License"); you may not use this file except in compliance with
-* the License. You may obtain a copy of the License at
-*
-* http://www.apache.org/licenses/LICENSE-2.0
-*
-* Unless required by applicable law or agreed to in writing, software
-* distributed under the License is distributed on an "AS IS" BASIS,
-* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-* See the License for the specific language governing permissions and
-* limitations under the License.
-*/
-
-package org.apache.poi.hssf.record.formula.eval;
-
-import org.apache.poi.hssf.record.formula.Area3DPtg;
-import org.apache.poi.hssf.record.formula.Ptg;
-
-/**
- * @author Amol S. Deshmukh &lt; amolweb at ya hoo dot com &gt;
- *
- */
-public final class Area3DEval extends AreaEvalBase {
-
- private final int _externSheetIndex;
-
- public Area3DEval(Ptg ptg, ValueEval[] values) {
- super((Area3DPtg) ptg, values);
- _externSheetIndex = ((Area3DPtg) ptg).getExternSheetIndex();
- }
-
- public int getExternSheetIndex() {
- return _externSheetIndex;
- }
-}
diff --git a/src/java/org/apache/poi/hssf/record/formula/eval/AreaEval.java b/src/java/org/apache/poi/hssf/record/formula/eval/AreaEval.java
index 182b9b618b..b528eb784e 100644
--- a/src/java/org/apache/poi/hssf/record/formula/eval/AreaEval.java
+++ b/src/java/org/apache/poi/hssf/record/formula/eval/AreaEval.java
@@ -62,13 +62,6 @@ public interface AreaEval extends ValueEval {
boolean isColumn();
/**
- * The array of values in this area. Although the area
- * maybe 1D (ie. isRow() or isColumn() returns true) or 2D
- * the returned array is 1D.
- */
- ValueEval[] getValues();
-
- /**
* @return the ValueEval from within this area at the specified row and col index. Never
* <code>null</code> (possibly {@link BlankEval}). The specified indexes should be absolute
* indexes in the sheet and not relative indexes within the area.
@@ -104,4 +97,10 @@ public interface AreaEval extends ValueEval {
* specified indexes should relative to the top left corner of this area.
*/
ValueEval getRelativeValue(int relativeRowIndex, int relativeColumnIndex);
+
+ /**
+ * Creates an {@link AreaEval} offset by a relative amount from from the upper left cell
+ * of this area
+ */
+ AreaEval offset(int relFirstRowIx, int relLastRowIx, int relFirstColIx, int relLastColIx);
}
diff --git a/src/java/org/apache/poi/hssf/record/formula/eval/AreaEvalBase.java b/src/java/org/apache/poi/hssf/record/formula/eval/AreaEvalBase.java
index 1686e75f33..94f6c9fe4a 100644
--- a/src/java/org/apache/poi/hssf/record/formula/eval/AreaEvalBase.java
+++ b/src/java/org/apache/poi/hssf/record/formula/eval/AreaEvalBase.java
@@ -22,20 +22,16 @@ import org.apache.poi.hssf.record.formula.AreaI;
/**
* @author Josh Micich
*/
-abstract class AreaEvalBase implements AreaEval {
+public abstract class AreaEvalBase implements AreaEval {
private final int _firstColumn;
private final int _firstRow;
private final int _lastColumn;
private final int _lastRow;
- private final ValueEval[] _values;
private final int _nColumns;
private final int _nRows;
- protected AreaEvalBase(AreaI ptg, ValueEval[] values) {
- if (values == null) {
- throw new IllegalArgumentException("values must not be null");
- }
+ protected AreaEvalBase(AreaI ptg) {
_firstRow = ptg.getFirstRow();
_firstColumn = ptg.getFirstColumn();
_lastRow = ptg.getLastRow();
@@ -43,22 +39,6 @@ abstract class AreaEvalBase implements AreaEval {
_nColumns = _lastColumn - _firstColumn + 1;
_nRows = _lastRow - _firstRow + 1;
-
- int expectedItemCount = _nRows * _nColumns;
- if ((values.length != expectedItemCount)) {
- // Note - this math may need alteration when POI starts to support full column or full row refs
- throw new IllegalArgumentException("Array size should be (" + expectedItemCount
- + ") but was (" + values.length + ")");
- }
-
-
-
- for (int i = values.length - 1; i >= 0; i--) {
- if (values[i] == null) {
- throw new IllegalArgumentException("value array elements must not be null");
- }
- }
- _values = values;
}
public final int getFirstColumn() {
@@ -77,11 +57,6 @@ abstract class AreaEvalBase implements AreaEval {
return _lastRow;
}
- public final ValueEval[] getValues() {
- // TODO - clone() - but some junits rely on not cloning at the moment
- return _values;
- }
-
public final ValueEval getValueAt(int row, int col) {
int rowOffsetIx = row - _firstRow;
int colOffsetIx = col - _firstColumn;
@@ -121,14 +96,7 @@ abstract class AreaEvalBase implements AreaEval {
return _lastRow-_firstRow+1;
}
- public ValueEval getRelativeValue(int relativeRowIndex, int relativeColumnIndex) {
- int index = relativeRowIndex * _nColumns + relativeColumnIndex;
- ValueEval result = _values[index];
- if (result == null) {
- return BlankEval.INSTANCE;
- }
- return result;
- }
+ public abstract ValueEval getRelativeValue(int relativeRowIndex, int relativeColumnIndex);
public int getWidth() {
return _lastColumn-_firstColumn+1;
diff --git a/src/java/org/apache/poi/hssf/record/formula/eval/FunctionEval.java b/src/java/org/apache/poi/hssf/record/formula/eval/FunctionEval.java
index 533c604a0c..fe58c69c09 100644
--- a/src/java/org/apache/poi/hssf/record/formula/eval/FunctionEval.java
+++ b/src/java/org/apache/poi/hssf/record/formula/eval/FunctionEval.java
@@ -50,7 +50,6 @@ public abstract class FunctionEval implements OperationEval {
static {
Map m = new HashMap();
- addMapping(m, ID.OFFSET, new Offset());
addMapping(m, ID.INDIRECT, new Indirect());
addMapping(m, ID.EXTERNAL_FUNC, new ExternalFunction());
freeRefFunctionsByIdMap = m;
@@ -155,7 +154,7 @@ public abstract class FunctionEval implements OperationEval {
retval[75] = new Areas(); // AREAS
retval[76] = new Rows(); // ROWS
retval[77] = new Columns(); // COLUMNS
- retval[ID.OFFSET] = null; // Offset.evaluate has a different signature
+ retval[ID.OFFSET] = new Offset(); // OFFSET
retval[79] = new Absref(); // ABSREF
retval[80] = new Relref(); // RELREF
retval[81] = new Argument(); // ARGUMENT
diff --git a/src/java/org/apache/poi/hssf/record/formula/eval/LazyAreaEval.java b/src/java/org/apache/poi/hssf/record/formula/eval/LazyAreaEval.java
new file mode 100644
index 0000000000..b5c6336170
--- /dev/null
+++ b/src/java/org/apache/poi/hssf/record/formula/eval/LazyAreaEval.java
@@ -0,0 +1,65 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one or more
+* contributor license agreements. See the NOTICE file distributed with
+* this work for additional information regarding copyright ownership.
+* The ASF licenses this file to You under the Apache License, Version 2.0
+* (the "License"); you may not use this file except in compliance with
+* the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+package org.apache.poi.hssf.record.formula.eval;
+
+import org.apache.poi.hssf.record.formula.AreaI;
+import org.apache.poi.hssf.record.formula.AreaI.OffsetArea;
+import org.apache.poi.ss.usermodel.Cell;
+import org.apache.poi.ss.usermodel.FormulaEvaluator;
+import org.apache.poi.ss.usermodel.Row;
+import org.apache.poi.ss.usermodel.Sheet;
+import org.apache.poi.ss.usermodel.Workbook;
+
+/**
+ * @author Amol S. Deshmukh &lt; amolweb at ya hoo dot com &gt;
+ *
+ */
+public final class LazyAreaEval extends AreaEvalBase {
+
+ private final Sheet _sheet;
+ private Workbook _workbook;
+
+ public LazyAreaEval(AreaI ptg, Sheet sheet, Workbook workbook) {
+ super(ptg);
+ _sheet = sheet;
+ _workbook = workbook;
+ }
+
+ public ValueEval getRelativeValue(int relativeRowIndex, int relativeColumnIndex) {
+
+ int rowIx = (relativeRowIndex + getFirstRow() ) & 0xFFFF;
+ int colIx = (relativeColumnIndex + getFirstColumn() ) & 0x00FF;
+
+ Row row = _sheet.getRow(rowIx);
+ if (row == null) {
+ return BlankEval.INSTANCE;
+ }
+ Cell cell = row.getCell(colIx);
+ if (cell == null) {
+ return BlankEval.INSTANCE;
+ }
+ return FormulaEvaluator.getEvalForCell(cell, _sheet, _workbook);
+ }
+
+ public AreaEval offset(int relFirstRowIx, int relLastRowIx, int relFirstColIx, int relLastColIx) {
+ AreaI area = new OffsetArea(getFirstRow(), getFirstColumn(),
+ relFirstRowIx, relLastRowIx, relFirstColIx, relLastColIx);
+
+ return new LazyAreaEval(area, _sheet, _workbook);
+ }
+}
diff --git a/src/java/org/apache/poi/hssf/record/formula/eval/LazyRefEval.java b/src/java/org/apache/poi/hssf/record/formula/eval/LazyRefEval.java
new file mode 100644
index 0000000000..7daf964240
--- /dev/null
+++ b/src/java/org/apache/poi/hssf/record/formula/eval/LazyRefEval.java
@@ -0,0 +1,52 @@
+package org.apache.poi.hssf.record.formula.eval;
+
+import org.apache.poi.hssf.record.formula.AreaI;
+import org.apache.poi.hssf.record.formula.AreaI.OffsetArea;
+import org.apache.poi.hssf.record.formula.Ref3DPtg;
+import org.apache.poi.hssf.record.formula.RefPtg;
+import org.apache.poi.ss.usermodel.Cell;
+import org.apache.poi.ss.usermodel.FormulaEvaluator;
+import org.apache.poi.ss.usermodel.Row;
+import org.apache.poi.ss.usermodel.Sheet;
+import org.apache.poi.ss.usermodel.Workbook;
+
+public final class LazyRefEval extends RefEvalBase {
+
+ private final Sheet _sheet;
+ private final Workbook _workbook;
+
+
+ public LazyRefEval(RefPtg ptg, Sheet sheet, Workbook workbook) {
+ super(ptg.getRow(), ptg.getColumn());
+ _sheet = sheet;
+ _workbook = workbook;
+ }
+ public LazyRefEval(Ref3DPtg ptg, Sheet sheet, Workbook workbook) {
+ super(ptg.getRow(), ptg.getColumn());
+ _sheet = sheet;
+ _workbook = workbook;
+ }
+
+ public ValueEval getInnerValueEval() {
+ int rowIx = getRow();
+ int colIx = getColumn();
+
+ Row row = _sheet.getRow(rowIx);
+ if (row == null) {
+ return BlankEval.INSTANCE;
+ }
+ Cell cell = row.getCell(colIx);
+ if (cell == null) {
+ return BlankEval.INSTANCE;
+ }
+ return FormulaEvaluator.getEvalForCell(cell, _sheet, _workbook);
+ }
+
+ public AreaEval offset(int relFirstRowIx, int relLastRowIx, int relFirstColIx, int relLastColIx) {
+
+ AreaI area = new OffsetArea(getRow(), getColumn(),
+ relFirstRowIx, relLastRowIx, relFirstColIx, relLastColIx);
+
+ return new LazyAreaEval(area, _sheet, _workbook);
+ }
+}
diff --git a/src/java/org/apache/poi/hssf/record/formula/eval/NumberEval.java b/src/java/org/apache/poi/hssf/record/formula/eval/NumberEval.java
index 44a017f631..e22957bd4a 100644
--- a/src/java/org/apache/poi/hssf/record/formula/eval/NumberEval.java
+++ b/src/java/org/apache/poi/hssf/record/formula/eval/NumberEval.java
@@ -69,5 +69,11 @@ public class NumberEval implements NumericValueEval, StringValueEval {
}
}
}
-
+ public final String toString() {
+ StringBuffer sb = new StringBuffer(64);
+ sb.append(getClass().getName()).append(" [");
+ sb.append(getStringValue());
+ sb.append("]");
+ return sb.toString();
+ }
}
diff --git a/src/java/org/apache/poi/hssf/record/formula/eval/Ref2DEval.java b/src/java/org/apache/poi/hssf/record/formula/eval/Ref2DEval.java
index 033ecc1f86..e4bb47a43d 100644
--- a/src/java/org/apache/poi/hssf/record/formula/eval/Ref2DEval.java
+++ b/src/java/org/apache/poi/hssf/record/formula/eval/Ref2DEval.java
@@ -47,4 +47,7 @@ public final class Ref2DEval implements RefEval {
public int getColumn() {
return delegate.getColumn();
}
+ public AreaEval offset(int relFirstRowIx, int relLastRowIx, int relFirstColIx, int relLastColIx) {
+ throw new RuntimeException("should not be called"); // TODO - delete this whole class
+ }
}
diff --git a/src/java/org/apache/poi/hssf/record/formula/eval/Ref3DEval.java b/src/java/org/apache/poi/hssf/record/formula/eval/Ref3DEval.java
deleted file mode 100644
index 622d686329..0000000000
--- a/src/java/org/apache/poi/hssf/record/formula/eval/Ref3DEval.java
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
-* Licensed to the Apache Software Foundation (ASF) under one or more
-* contributor license agreements. See the NOTICE file distributed with
-* this work for additional information regarding copyright ownership.
-* The ASF licenses this file to You under the Apache License, Version 2.0
-* (the "License"); you may not use this file except in compliance with
-* the License. You may obtain a copy of the License at
-*
-* http://www.apache.org/licenses/LICENSE-2.0
-*
-* Unless required by applicable law or agreed to in writing, software
-* distributed under the License is distributed on an "AS IS" BASIS,
-* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-* See the License for the specific language governing permissions and
-* limitations under the License.
-*/
-
-package org.apache.poi.hssf.record.formula.eval;
-
-import org.apache.poi.hssf.record.formula.Ref3DPtg;
-
-/**
- * @author Amol S. Deshmukh
- *
- */
-public final class Ref3DEval implements RefEval {
-
- private final ValueEval value;
- private final Ref3DPtg delegate;
-
- public Ref3DEval(Ref3DPtg ptg, ValueEval ve) {
- if(ve == null) {
- throw new IllegalArgumentException("ve must not be null");
- }
- if(ptg == null) {
- throw new IllegalArgumentException("ptg must not be null");
- }
- value = ve;
- delegate = ptg;
- }
- public ValueEval getInnerValueEval() {
- return value;
- }
- public int getRow() {
- return delegate.getRow();
- }
- public int getColumn() {
- return delegate.getColumn();
- }
- public int getExternSheetIndex() {
- return delegate.getExternSheetIndex();
- }
-}
diff --git a/src/java/org/apache/poi/hssf/record/formula/eval/RefEval.java b/src/java/org/apache/poi/hssf/record/formula/eval/RefEval.java
index e462586d72..397d1f1c94 100644
--- a/src/java/org/apache/poi/hssf/record/formula/eval/RefEval.java
+++ b/src/java/org/apache/poi/hssf/record/formula/eval/RefEval.java
@@ -1,19 +1,19 @@
-/*
-* 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.
-*/
+/* ====================================================================
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+==================================================================== */
package org.apache.poi.hssf.record.formula.eval;
@@ -30,22 +30,22 @@ package org.apache.poi.hssf.record.formula.eval;
public interface RefEval extends ValueEval {
/**
- * The (possibly evaluated) ValueEval contained
- * in this RefEval. eg. if cell A1 contains "test"
- * then in a formula referring to cell A1
- * the RefEval representing
- * A1 will return as the getInnerValueEval() the
- * object of concrete type StringEval
+ * @return the evaluated value of the cell referred to by this RefEval.
*/
- public ValueEval getInnerValueEval();
+ ValueEval getInnerValueEval();
/**
* returns the zero based column index.
*/
- public int getColumn();
+ int getColumn();
/**
* returns the zero based row index.
*/
- public int getRow();
+ int getRow();
+
+ /**
+ * Creates an {@link AreaEval} offset by a relative amount from this RefEval
+ */
+ AreaEval offset(int relFirstRowIx, int relLastRowIx, int relFirstColIx, int relLastColIx);
}
diff --git a/src/java/org/apache/poi/hssf/record/formula/eval/RefEvalBase.java b/src/java/org/apache/poi/hssf/record/formula/eval/RefEvalBase.java
new file mode 100644
index 0000000000..37d20f8082
--- /dev/null
+++ b/src/java/org/apache/poi/hssf/record/formula/eval/RefEvalBase.java
@@ -0,0 +1,18 @@
+package org.apache.poi.hssf.record.formula.eval;
+
+public abstract class RefEvalBase implements RefEval {
+
+ private final int _rowIndex;
+ private final int _columnIndex;
+
+ protected RefEvalBase(int rowIndex, int columnIndex) {
+ _rowIndex = rowIndex;
+ _columnIndex = columnIndex;
+ }
+ public final int getRow() {
+ return _rowIndex;
+ }
+ public final int getColumn() {
+ return _columnIndex;
+ }
+}
diff --git a/src/java/org/apache/poi/hssf/record/formula/functions/CountUtils.java b/src/java/org/apache/poi/hssf/record/formula/functions/CountUtils.java
index f8d8883825..27dfcc1b64 100644
--- a/src/java/org/apache/poi/hssf/record/formula/functions/CountUtils.java
+++ b/src/java/org/apache/poi/hssf/record/formula/functions/CountUtils.java
@@ -50,9 +50,9 @@ final class CountUtils {
for (int rrIx=0; rrIx<height; rrIx++) {
for (int rcIx=0; rcIx<width; rcIx++) {
ValueEval ve = areaEval.getRelativeValue(rrIx, rcIx);
- if(criteriaPredicate.matches(ve)) {
- result++;
- }
+ if(criteriaPredicate.matches(ve)) {
+ result++;
+ }
}
}
return result;
@@ -67,6 +67,9 @@ final class CountUtils {
return 0;
}
public static int countArg(Eval eval, I_MatchPredicate criteriaPredicate) {
+ if (eval == null) {
+ throw new IllegalArgumentException("eval must not be null");
+ }
if (eval instanceof AreaEval) {
return CountUtils.countMatchingCellsInArea((AreaEval) eval, criteriaPredicate);
}
diff --git a/src/java/org/apache/poi/hssf/record/formula/functions/If.java b/src/java/org/apache/poi/hssf/record/formula/functions/If.java
index 7aba5db72a..4b066b8226 100644
--- a/src/java/org/apache/poi/hssf/record/formula/functions/If.java
+++ b/src/java/org/apache/poi/hssf/record/formula/functions/If.java
@@ -1,28 +1,28 @@
-/*
-* 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.
-*/
-/*
- * Created on Nov 25, 2006
- *
- */
+/* ====================================================================
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+==================================================================== */
+
package org.apache.poi.hssf.record.formula.functions;
import org.apache.poi.hssf.record.formula.eval.BoolEval;
import org.apache.poi.hssf.record.formula.eval.ErrorEval;
import org.apache.poi.hssf.record.formula.eval.Eval;
+import org.apache.poi.hssf.record.formula.eval.EvaluationException;
+import org.apache.poi.hssf.record.formula.eval.OperandResolver;
+import org.apache.poi.hssf.record.formula.eval.ValueEval;
/**
* @author Amol S. Deshmukh &lt; amolweb at ya hoo dot com &gt;
@@ -30,20 +30,37 @@ import org.apache.poi.hssf.record.formula.eval.Eval;
*/
public final class If implements Function {
- public Eval evaluate(Eval[] args, int srcCellRow, short srcCellCol) {
+ public Eval evaluate(Eval[] args, int srcCellRow, short srcCellCol) {
+ Eval falseResult;
+ switch (args.length) {
+ case 3:
+ falseResult = args[2];
+ break;
+ case 2:
+ falseResult = BoolEval.FALSE;
+ break;
+ default:
+ return ErrorEval.VALUE_INVALID;
+ }
+ boolean b;
+ try {
+ b = evaluateFirstArg(args[0], srcCellRow, srcCellCol);
+ } catch (EvaluationException e) {
+ return e.getErrorEval();
+ }
+ if (b) {
+ return args[1];
+ }
+ return falseResult;
+ }
- Eval evalWhenFalse = BoolEval.FALSE;
- switch (args.length) {
- case 3:
- evalWhenFalse = args[2];
- case 2:
- BoolEval beval = (BoolEval) args[0]; // TODO - class cast exception
- if (beval.getBooleanValue()) {
- return args[1];
- }
- return evalWhenFalse;
- default:
- return ErrorEval.VALUE_INVALID;
- }
- }
+ private static boolean evaluateFirstArg(Eval arg, int srcCellRow, short srcCellCol)
+ throws EvaluationException {
+ ValueEval ve = OperandResolver.getSingleValue(arg, srcCellRow, srcCellCol);
+ Boolean b = OperandResolver.coerceValueToBoolean(ve, false);
+ if (b == null) {
+ return false;
+ }
+ return b.booleanValue();
+ }
}
diff --git a/src/java/org/apache/poi/hssf/record/formula/functions/Index.java b/src/java/org/apache/poi/hssf/record/formula/functions/Index.java
index aebf6aab0d..3c93c0846b 100644
--- a/src/java/org/apache/poi/hssf/record/formula/functions/Index.java
+++ b/src/java/org/apache/poi/hssf/record/formula/functions/Index.java
@@ -1,28 +1,28 @@
-/*
-* 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.
-*/
+/* ====================================================================
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+==================================================================== */
package org.apache.poi.hssf.record.formula.functions;
import org.apache.poi.hssf.record.formula.eval.AreaEval;
import org.apache.poi.hssf.record.formula.eval.ErrorEval;
import org.apache.poi.hssf.record.formula.eval.Eval;
-import org.apache.poi.hssf.record.formula.eval.NumberEval;
-import org.apache.poi.hssf.record.formula.eval.RefEval;
+import org.apache.poi.hssf.record.formula.eval.EvaluationException;
+import org.apache.poi.hssf.record.formula.eval.OperandResolver;
+import org.apache.poi.hssf.record.formula.eval.ValueEval;
/**
* Implementation for the Excel function INDEX<p/>
@@ -51,15 +51,23 @@ public final class Index implements Function {
return ErrorEval.VALUE_INVALID;
}
Eval firstArg = args[0];
- if(firstArg instanceof AreaEval) {
- AreaEval reference = (AreaEval) firstArg;
+ if(!(firstArg instanceof AreaEval)) {
+
+ // else the other variation of this function takes an array as the first argument
+ // it seems like interface 'ArrayEval' does not even exist yet
- int rowIx = 0;
- int columnIx = 0;
- int areaIx = 0;
+ throw new RuntimeException("Incomplete code - cannot handle first arg of type ("
+ + firstArg.getClass().getName() + ")");
+ }
+ AreaEval reference = (AreaEval) firstArg;
+
+ int rowIx = 0;
+ int columnIx = 0;
+ int areaIx = 0;
+ try {
switch(nArgs) {
case 4:
- areaIx = convertIndexArgToZeroBase(args[3]);
+ areaIx = convertIndexArgToZeroBase(args[3], srcCellRow, srcCellCol);
throw new RuntimeException("Incomplete code" +
" - don't know how to support the 'area_num' parameter yet)");
// Excel expression might look like this "INDEX( (A1:B4, C3:D6, D2:E5 ), 1, 2, 3)
@@ -68,41 +76,41 @@ public final class Index implements Function {
// The formula parser doesn't seem to support this yet. Not sure if the evaluator does either
case 3:
- columnIx = convertIndexArgToZeroBase(args[2]);
+ columnIx = convertIndexArgToZeroBase(args[2], srcCellRow, srcCellCol);
case 2:
- rowIx = convertIndexArgToZeroBase(args[1]);
+ rowIx = convertIndexArgToZeroBase(args[1], srcCellRow, srcCellCol);
break;
default:
// too many arguments
return ErrorEval.VALUE_INVALID;
}
-
- int nColumns = reference.getLastColumn()-reference.getFirstColumn()+1;
- int index = rowIx * nColumns + columnIx;
-
- return reference.getValues()[index];
+ return getValueFromArea(reference, rowIx, columnIx);
+ } catch (EvaluationException e) {
+ return e.getErrorEval();
}
-
- // else the other variation of this function takes an array as the first argument
- // it seems like interface 'ArrayEval' does not even exist yet
-
- throw new RuntimeException("Incomplete code - cannot handle first arg of type ("
- + firstArg.getClass().getName() + ")");
}
+ private static ValueEval getValueFromArea(AreaEval ae, int rowIx, int columnIx) throws EvaluationException {
+ int width = ae.getWidth();
+ int height = ae.getHeight();
+
+ // Slightly irregular logic for bounds checking errors
+ if (rowIx >= height || columnIx >= width) {
+ throw new EvaluationException(ErrorEval.REF_INVALID);
+ }
+ if (rowIx < 0 || columnIx < 0) {
+ throw new EvaluationException(ErrorEval.VALUE_INVALID);
+ }
+ return ae.getRelativeValue(rowIx, columnIx);
+ }
+
/**
* takes a NumberEval representing a 1-based index and returns the zero-based int value
*/
- private static int convertIndexArgToZeroBase(Eval ev) {
- NumberEval ne;
- if(ev instanceof RefEval) {
- // TODO - write junit to justify this
- RefEval re = (RefEval) ev;
- ne = (NumberEval) re.getInnerValueEval();
- } else {
- ne = (NumberEval)ev;
- }
+ private static int convertIndexArgToZeroBase(Eval arg, int srcCellRow, short srcCellCol) throws EvaluationException {
- return (int)ne.getNumberValue() - 1;
+ ValueEval ev = OperandResolver.getSingleValue(arg, srcCellRow, srcCellCol);
+ int oneBasedVal = OperandResolver.coerceValueToInt(ev);
+ return oneBasedVal - 1;
}
}
diff --git a/src/java/org/apache/poi/hssf/record/formula/functions/LookupUtils.java b/src/java/org/apache/poi/hssf/record/formula/functions/LookupUtils.java
index e8c083dc5a..e6a3ec81c2 100644
--- a/src/java/org/apache/poi/hssf/record/formula/functions/LookupUtils.java
+++ b/src/java/org/apache/poi/hssf/record/formula/functions/LookupUtils.java
@@ -17,8 +17,6 @@
package org.apache.poi.hssf.record.formula.functions;
-import org.apache.poi.hssf.record.formula.AreaPtg;
-import org.apache.poi.hssf.record.formula.eval.Area2DEval;
import org.apache.poi.hssf.record.formula.eval.AreaEval;
import org.apache.poi.hssf.record.formula.eval.BlankEval;
import org.apache.poi.hssf.record.formula.eval.BoolEval;
@@ -366,13 +364,7 @@ final class LookupUtils {
// Make this cell ref look like a 1x1 area ref.
// It doesn't matter if eval is a 2D or 3D ref, because that detail is never asked of AreaEval.
- // This code only requires the value array item.
- // anything would be ok for rowIx and colIx, but may as well get it right.
- int rowIx = refEval.getRow();
- int colIx = refEval.getColumn();
- AreaPtg ap = new AreaPtg(rowIx, rowIx, colIx, colIx, false, false, false, false);
- ValueEval value = refEval.getInnerValueEval();
- return new Area2DEval(ap, new ValueEval[] { value, });
+ return refEval.offset(0, 0, 0, 0);
}
throw EvaluationException.invalidValue();
}
diff --git a/src/java/org/apache/poi/hssf/record/formula/functions/MathX.java b/src/java/org/apache/poi/hssf/record/formula/functions/MathX.java
index 593998f1e9..311707665e 100644
--- a/src/java/org/apache/poi/hssf/record/formula/functions/MathX.java
+++ b/src/java/org/apache/poi/hssf/record/formula/functions/MathX.java
@@ -455,85 +455,6 @@ public final class MathX {
return d;
}
- /**
- * returns the sum of difference of squares of corresponding double
- * value in each subarray: ie. sigma (xarr[i]^2-yarr[i]^2)
- * <br/>
- * It is the responsibility of the caller
- * to ensure that the two subarrays are of equal length. If the
- * subarrays are not of equal length, the return value can be
- * unpredictable.
- * @param xarr
- * @param yarr
- */
- public static double sumx2my2(double[] xarr, double[] yarr) {
- double d = 0;
-
- try {
- for (int i=0, iSize=xarr.length; i<iSize; i++) {
- d += (xarr[i] + yarr[i]) * (xarr[i] - yarr[i]);
- }
- }
- catch (ArrayIndexOutOfBoundsException ae) {
- d = Double.NaN;
- }
-
- return d;
- }
-
- /**
- * returns the sum of sum of squares of corresponding double
- * value in each subarray: ie. sigma (xarr[i]^2 + yarr[i]^2)
- * <br/>
- * It is the responsibility of the caller
- * to ensure that the two subarrays are of equal length. If the
- * subarrays are not of equal length, the return value can be
- * unpredictable.
- * @param xarr
- * @param yarr
- */
- public static double sumx2py2(double[] xarr, double[] yarr) {
- double d = 0;
-
- try {
- for (int i=0, iSize=xarr.length; i<iSize; i++) {
- d += (xarr[i] * xarr[i]) + (yarr[i] * yarr[i]);
- }
- }
- catch (ArrayIndexOutOfBoundsException ae) {
- d = Double.NaN;
- }
-
- return d;
- }
-
-
- /**
- * returns the sum of squares of difference of corresponding double
- * value in each subarray: ie. sigma ( (xarr[i]-yarr[i])^2 )
- * <br/>
- * It is the responsibility of the caller
- * to ensure that the two subarrays are of equal length. If the
- * subarrays are not of equal length, the return value can be
- * unpredictable.
- * @param xarr
- * @param yarr
- */
- public static double sumxmy2(double[] xarr, double[] yarr) {
- double d = 0;
-
- try {
- for (int i=0, iSize=xarr.length; i<iSize; i++) {
- double t = (xarr[i] - yarr[i]);
- d += t * t;
- }
- }
- catch (ArrayIndexOutOfBoundsException ae) {
- d = Double.NaN;
- }
-
- return d;
- }
/**
* returns the total number of combinations possible when
diff --git a/src/java/org/apache/poi/hssf/record/formula/functions/MultiOperandNumericFunction.java b/src/java/org/apache/poi/hssf/record/formula/functions/MultiOperandNumericFunction.java
index 0e7cce217e..a9e98ae313 100644
--- a/src/java/org/apache/poi/hssf/record/formula/functions/MultiOperandNumericFunction.java
+++ b/src/java/org/apache/poi/hssf/record/formula/functions/MultiOperandNumericFunction.java
@@ -126,30 +126,34 @@ public abstract class MultiOperandNumericFunction extends NumericFunction {
if (operand instanceof AreaEval) {
AreaEval ae = (AreaEval) operand;
- ValueEval[] values = ae.getValues();
DoubleList retval = new DoubleList();
- for (int j=0, jSize=values.length; j<jSize; j++) {
- /*
- * TODO: For an AreaEval, we are constructing a RefEval
- * per element.
- * For now this is a tempfix solution since this may
- * require a more generic fix at the level of
- * HSSFFormulaEvaluator where we store an array
- * of RefEvals as the "values" array.
- */
- RefEval re = new Ref2DEval(null, values[j]);
- ValueEval ve = singleOperandEvaluate(re, srcRow, srcCol);
-
- if (ve instanceof NumericValueEval) {
- NumericValueEval nve = (NumericValueEval) ve;
- retval.add(nve.getNumberValue());
- }
- else if (ve instanceof BlankEval) {
- // note - blanks are ignored, so returned array will be smaller.
- }
- else {
- return null; // indicate to calling subclass that error occurred
- }
+ int width = ae.getWidth();
+ int height = ae.getHeight();
+ for (int rrIx=0; rrIx<height; rrIx++) {
+ for (int rcIx=0; rcIx<width; rcIx++) {
+ ValueEval ve1 = ae.getRelativeValue(rrIx, rcIx);
+ /*
+ * TODO: For an AreaEval, we are constructing a RefEval
+ * per element.
+ * For now this is a tempfix solution since this may
+ * require a more generic fix at the level of
+ * HSSFFormulaEvaluator where we store an array
+ * of RefEvals as the "values" array.
+ */
+ RefEval re = new Ref2DEval(null, ve1);
+ ValueEval ve = singleOperandEvaluate(re, srcRow, srcCol);
+
+ if (ve instanceof NumericValueEval) {
+ NumericValueEval nve = (NumericValueEval) ve;
+ retval.add(nve.getNumberValue());
+ }
+ else if (ve instanceof BlankEval) {
+ // note - blanks are ignored, so returned array will be smaller.
+ }
+ else {
+ return null; // indicate to calling subclass that error occurred
+ }
+ }
}
return retval.toArray();
}
diff --git a/src/java/org/apache/poi/hssf/record/formula/functions/Offset.java b/src/java/org/apache/poi/hssf/record/formula/functions/Offset.java
index 08bdf3d64c..086596ae21 100644
--- a/src/java/org/apache/poi/hssf/record/formula/functions/Offset.java
+++ b/src/java/org/apache/poi/hssf/record/formula/functions/Offset.java
@@ -1,26 +1,22 @@
-/*
-* 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.
-*/
+/* ====================================================================
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+==================================================================== */
package org.apache.poi.hssf.record.formula.functions;
-import org.apache.poi.hssf.record.formula.Area3DPtg;
-import org.apache.poi.hssf.record.formula.AreaPtg;
-import org.apache.poi.hssf.record.formula.eval.Area3DEval;
import org.apache.poi.hssf.record.formula.eval.AreaEval;
import org.apache.poi.hssf.record.formula.eval.BoolEval;
import org.apache.poi.hssf.record.formula.eval.ErrorEval;
@@ -28,13 +24,9 @@ import org.apache.poi.hssf.record.formula.eval.Eval;
import org.apache.poi.hssf.record.formula.eval.EvaluationException;
import org.apache.poi.hssf.record.formula.eval.NumericValueEval;
import org.apache.poi.hssf.record.formula.eval.OperandResolver;
-import org.apache.poi.hssf.record.formula.eval.Ref3DEval;
import org.apache.poi.hssf.record.formula.eval.RefEval;
import org.apache.poi.hssf.record.formula.eval.StringEval;
import org.apache.poi.hssf.record.formula.eval.ValueEval;
-import org.apache.poi.hssf.usermodel.HSSFFormulaEvaluator;
-import org.apache.poi.ss.usermodel.Sheet;
-import org.apache.poi.ss.usermodel.Workbook;
/**
* Implementation for Excel function OFFSET()<p/>
*
@@ -51,7 +43,7 @@ import org.apache.poi.ss.usermodel.Workbook;
*
* @author Josh Micich
*/
-public final class Offset implements FreeRefFunction {
+public final class Offset implements Function {
// These values are specific to BIFF8
private static final int LAST_VALID_ROW_INDEX = 0xFFFF;
private static final int LAST_VALID_COLUMN_INDEX = 0xFF;
@@ -125,37 +117,29 @@ public final class Offset implements FreeRefFunction {
* Encapsulates either an area or cell reference which may be 2d or 3d.
*/
private static final class BaseRef {
- private static final int INVALID_SHEET_INDEX = -1;
private final int _firstRowIndex;
private final int _firstColumnIndex;
private final int _width;
private final int _height;
- private final int _externalSheetIndex;
+ private final RefEval _refEval;
+ private final AreaEval _areaEval;
public BaseRef(RefEval re) {
+ _refEval = re;
+ _areaEval = null;
_firstRowIndex = re.getRow();
_firstColumnIndex = re.getColumn();
_height = 1;
_width = 1;
- if (re instanceof Ref3DEval) {
- Ref3DEval r3e = (Ref3DEval) re;
- _externalSheetIndex = r3e.getExternSheetIndex();
- } else {
- _externalSheetIndex = INVALID_SHEET_INDEX;
- }
}
public BaseRef(AreaEval ae) {
+ _refEval = null;
+ _areaEval = ae;
_firstRowIndex = ae.getFirstRow();
_firstColumnIndex = ae.getFirstColumn();
_height = ae.getLastRow() - ae.getFirstRow() + 1;
_width = ae.getLastColumn() - ae.getFirstColumn() + 1;
- if (ae instanceof Area3DEval) {
- Area3DEval a3e = (Area3DEval) ae;
- _externalSheetIndex = a3e.getExternSheetIndex();
- } else {
- _externalSheetIndex = INVALID_SHEET_INDEX;
- }
}
public int getWidth() {
@@ -170,20 +154,17 @@ public final class Offset implements FreeRefFunction {
public int getFirstColumnIndex() {
return _firstColumnIndex;
}
- public boolean isIs3d() {
- return _externalSheetIndex > 0;
- }
- public short getExternalSheetIndex() {
- if(_externalSheetIndex < 0) {
- throw new IllegalStateException("external sheet index only available for 3d refs");
+ public AreaEval offset(int relFirstRowIx, int relLastRowIx,
+ int relFirstColIx, int relLastColIx) {
+ if (_refEval == null) {
+ return _areaEval.offset(relFirstRowIx, relLastRowIx, relFirstColIx, relLastColIx);
}
- return (short) _externalSheetIndex;
+ return _refEval.offset(relFirstRowIx, relLastRowIx, relFirstColIx, relLastColIx);
}
}
- public ValueEval evaluate(Eval[] args, int srcCellRow, short srcCellCol, Workbook workbook, Sheet sheet) {
-
+ public Eval evaluate(Eval[] args, int srcCellRow, short srcCellCol) {
if(args.length < 3 || args.length > 5) {
return ErrorEval.VALUE_INVALID;
}
@@ -206,37 +187,24 @@ public final class Offset implements FreeRefFunction {
}
LinearOffsetRange rowOffsetRange = new LinearOffsetRange(rowOffset, height);
LinearOffsetRange colOffsetRange = new LinearOffsetRange(columnOffset, width);
- return createOffset(baseRef, rowOffsetRange, colOffsetRange, workbook, sheet);
+ return createOffset(baseRef, rowOffsetRange, colOffsetRange);
} catch (EvaluationException e) {
return e.getErrorEval();
}
}
private static AreaEval createOffset(BaseRef baseRef,
- LinearOffsetRange rowOffsetRange, LinearOffsetRange colOffsetRange,
- Workbook workbook, Sheet sheet) throws EvaluationException {
-
- LinearOffsetRange rows = rowOffsetRange.normaliseAndTranslate(baseRef.getFirstRowIndex());
- LinearOffsetRange cols = colOffsetRange.normaliseAndTranslate(baseRef.getFirstColumnIndex());
+ LinearOffsetRange orRow, LinearOffsetRange orCol) throws EvaluationException {
+ LinearOffsetRange absRows = orRow.normaliseAndTranslate(baseRef.getFirstRowIndex());
+ LinearOffsetRange absCols = orCol.normaliseAndTranslate(baseRef.getFirstColumnIndex());
- if(rows.isOutOfBounds(0, LAST_VALID_ROW_INDEX)) {
+ if(absRows.isOutOfBounds(0, LAST_VALID_ROW_INDEX)) {
throw new EvaluationException(ErrorEval.REF_INVALID);
}
- if(cols.isOutOfBounds(0, LAST_VALID_COLUMN_INDEX)) {
+ if(absCols.isOutOfBounds(0, LAST_VALID_COLUMN_INDEX)) {
throw new EvaluationException(ErrorEval.REF_INVALID);
}
- if(baseRef.isIs3d()) {
- Area3DPtg a3dp = new Area3DPtg(rows.getFirstIndex(), rows.getLastIndex(),
- cols.getFirstIndex(), cols.getLastIndex(),
- false, false, false, false,
- baseRef.getExternalSheetIndex());
- return HSSFFormulaEvaluator.evaluateArea3dPtg(workbook, a3dp);
- }
-
- AreaPtg ap = new AreaPtg(rows.getFirstIndex(), rows.getLastIndex(),
- cols.getFirstIndex(), cols.getLastIndex(),
- false, false, false, false);
- return HSSFFormulaEvaluator.evaluateAreaPtg(sheet, workbook, ap);
+ return baseRef.offset(orRow.getFirstIndex(), orRow.getLastIndex(), orCol.getFirstIndex(), orCol.getLastIndex());
}
private static BaseRef evaluateBaseRef(Eval eval) throws EvaluationException {
diff --git a/src/java/org/apache/poi/hssf/record/formula/functions/Sumx2my2.java b/src/java/org/apache/poi/hssf/record/formula/functions/Sumx2my2.java
index 30ad5ec230..4dedf26574 100644
--- a/src/java/org/apache/poi/hssf/record/formula/functions/Sumx2my2.java
+++ b/src/java/org/apache/poi/hssf/record/formula/functions/Sumx2my2.java
@@ -1,22 +1,23 @@
-/*
-* 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.
-*/
+/* ====================================================================
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+==================================================================== */
package org.apache.poi.hssf.record.formula.functions;
+
/**
* Implementation of Excel function SUMX2MY2()<p/>
*
@@ -30,7 +31,13 @@ package org.apache.poi.hssf.record.formula.functions;
*/
public final class Sumx2my2 extends XYNumericFunction {
- protected double evaluate(double[] xArray, double[] yArray) {
- return MathX.sumx2my2(xArray, yArray);
- }
+ private static final Accumulator XSquaredMinusYSquaredAccumulator = new Accumulator() {
+ public double accumulate(double x, double y) {
+ return x * x - y * y;
+ }
+ };
+
+ protected Accumulator createAccumulator() {
+ return XSquaredMinusYSquaredAccumulator;
+ }
}
diff --git a/src/java/org/apache/poi/hssf/record/formula/functions/Sumx2py2.java b/src/java/org/apache/poi/hssf/record/formula/functions/Sumx2py2.java
index dfd730d12c..c3af0bd380 100644
--- a/src/java/org/apache/poi/hssf/record/formula/functions/Sumx2py2.java
+++ b/src/java/org/apache/poi/hssf/record/formula/functions/Sumx2py2.java
@@ -1,22 +1,23 @@
-/*
-* 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.
-*/
+/* ====================================================================
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+==================================================================== */
package org.apache.poi.hssf.record.formula.functions;
+
/**
* Implementation of Excel function SUMX2PY2()<p/>
*
@@ -30,7 +31,13 @@ package org.apache.poi.hssf.record.formula.functions;
*/
public final class Sumx2py2 extends XYNumericFunction {
- protected double evaluate(double[] xArray, double[] yArray) {
- return MathX.sumx2py2(xArray, yArray);
- }
+ private static final Accumulator XSquaredPlusYSquaredAccumulator = new Accumulator() {
+ public double accumulate(double x, double y) {
+ return x * x + y * y;
+ }
+ };
+
+ protected Accumulator createAccumulator() {
+ return XSquaredPlusYSquaredAccumulator;
+ }
}
diff --git a/src/java/org/apache/poi/hssf/record/formula/functions/Sumxmy2.java b/src/java/org/apache/poi/hssf/record/formula/functions/Sumxmy2.java
index a1b2fec9b2..4fa11e36ba 100644
--- a/src/java/org/apache/poi/hssf/record/formula/functions/Sumxmy2.java
+++ b/src/java/org/apache/poi/hssf/record/formula/functions/Sumxmy2.java
@@ -1,19 +1,19 @@
-/*
-* 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.
-*/
+/* ====================================================================
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+==================================================================== */
package org.apache.poi.hssf.record.formula.functions;
@@ -30,7 +30,14 @@ package org.apache.poi.hssf.record.formula.functions;
*/
public final class Sumxmy2 extends XYNumericFunction {
- protected double evaluate(double[] xArray, double[] yArray) {
- return MathX.sumxmy2(xArray, yArray);
- }
+ private static final Accumulator XMinusYSquaredAccumulator = new Accumulator() {
+ public double accumulate(double x, double y) {
+ double xmy = x - y;
+ return xmy * xmy;
+ }
+ };
+
+ protected Accumulator createAccumulator() {
+ return XMinusYSquaredAccumulator;
+ }
}
diff --git a/src/java/org/apache/poi/hssf/record/formula/functions/XYNumericFunction.java b/src/java/org/apache/poi/hssf/record/formula/functions/XYNumericFunction.java
index b989c33a26..1d83b363fd 100644
--- a/src/java/org/apache/poi/hssf/record/formula/functions/XYNumericFunction.java
+++ b/src/java/org/apache/poi/hssf/record/formula/functions/XYNumericFunction.java
@@ -1,19 +1,19 @@
-/*
-* 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.
-*/
+/* ====================================================================
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+==================================================================== */
package org.apache.poi.hssf.record.formula.functions;
@@ -24,180 +24,162 @@ import org.apache.poi.hssf.record.formula.eval.EvaluationException;
import org.apache.poi.hssf.record.formula.eval.NumberEval;
import org.apache.poi.hssf.record.formula.eval.RefEval;
import org.apache.poi.hssf.record.formula.eval.ValueEval;
+import org.apache.poi.hssf.record.formula.functions.LookupUtils.ValueVector;
/**
* @author Amol S. Deshmukh &lt; amolweb at ya hoo dot com &gt;
- *
+ *
*/
public abstract class XYNumericFunction implements Function {
- protected static final int X = 0;
- protected static final int Y = 1;
-
- protected static final class DoubleArrayPair {
- private final double[] _xArray;
- private final double[] _yArray;
+ private static abstract class ValueArray implements ValueVector {
+ private final int _size;
+ protected ValueArray(int size) {
+ _size = size;
+ }
+ public ValueEval getItem(int index) {
+ if (index < 0 || index > _size) {
+ throw new IllegalArgumentException("Specified index " + index
+ + " is outside range (0.." + (_size - 1) + ")");
+ }
+ return getItemInternal(index);
+ }
+ protected abstract ValueEval getItemInternal(int index);
+ public final int getSize() {
+ return _size;
+ }
+ }
- public DoubleArrayPair(double[] xArray, double[] yArray) {
- _xArray = xArray;
- _yArray = yArray;
+ private static final class SingleCellValueArray extends ValueArray {
+ private final ValueEval _value;
+ public SingleCellValueArray(ValueEval value) {
+ super(1);
+ _value = value;
}
- public double[] getXArray() {
- return _xArray;
+ protected ValueEval getItemInternal(int index) {
+ return _value;
+ }
+ }
+
+ private static final class RefValueArray extends ValueArray {
+ private final RefEval _ref;
+ public RefValueArray(RefEval ref) {
+ super(1);
+ _ref = ref;
}
- public double[] getYArray() {
- return _yArray;
+ protected ValueEval getItemInternal(int index) {
+ return _ref.getInnerValueEval();
}
- }
+ }
+ private static final class AreaValueArray extends ValueArray {
+ private final AreaEval _ae;
+ private final int _width;
+
+ public AreaValueArray(AreaEval ae) {
+ super(ae.getWidth() * ae.getHeight());
+ _ae = ae;
+ _width = ae.getWidth();
+ }
+ protected ValueEval getItemInternal(int index) {
+ int rowIx = index / _width;
+ int colIx = index % _width;
+ return _ae.getRelativeValue(rowIx, colIx);
+ }
+ }
+
+ protected static interface Accumulator {
+ double accumulate(double x, double y);
+ }
+
+ /**
+ * Constructs a new instance of the Accumulator used to calculated this function
+ */
+ protected abstract Accumulator createAccumulator();
+
+ public final Eval evaluate(Eval[] args, int srcCellRow, short srcCellCol) {
+ if (args.length != 2) {
+ return ErrorEval.VALUE_INVALID;
+ }
- public final Eval evaluate(Eval[] args, int srcCellRow, short srcCellCol) {
- if(args.length != 2) {
- return ErrorEval.VALUE_INVALID;
- }
-
- double[][] values;
+ double result;
try {
- values = getValues(args[0], args[1]);
+ ValueVector vvX = createValueVector(args[0]);
+ ValueVector vvY = createValueVector(args[1]);
+ int size = vvX.getSize();
+ if (size == 0 || vvY.getSize() != size) {
+ return ErrorEval.NA;
+ }
+ result = evaluateInternal(vvX, vvY, size);
} catch (EvaluationException e) {
return e.getErrorEval();
}
- if (values==null
- || values[X] == null || values[Y] == null
- || values[X].length == 0 || values[Y].length == 0
- || values[X].length != values[Y].length) {
- return ErrorEval.VALUE_INVALID;
- }
-
- double d = evaluate(values[X], values[Y]);
- if (Double.isNaN(d) || Double.isInfinite(d)) {
+ if (Double.isNaN(result) || Double.isInfinite(result)) {
return ErrorEval.NUM_ERROR;
}
- return new NumberEval(d);
- }
- protected abstract double evaluate(double[] xArray, double[] yArray);
-
- /**
- * Returns a double array that contains values for the numeric cells
- * from among the list of operands. Blanks and Blank equivalent cells
- * are ignored. Error operands or cells containing operands of type
- * that are considered invalid and would result in #VALUE! error in
- * excel cause this function to return null.
- */
- private static double[][] getNumberArray(Eval[] xops, Eval[] yops) throws EvaluationException {
-
- // check for errors first: size mismatch, value errors in x, value errors in y
-
- int nArrayItems = xops.length;
- if(nArrayItems != yops.length) {
- throw new EvaluationException(ErrorEval.NA);
- }
- for (int i = 0; i < xops.length; i++) {
- Eval eval = xops[i];
- if (eval instanceof ErrorEval) {
- throw new EvaluationException((ErrorEval) eval);
+ return new NumberEval(result);
+ }
+
+ private double evaluateInternal(ValueVector x, ValueVector y, int size)
+ throws EvaluationException {
+ Accumulator acc = createAccumulator();
+
+ // error handling is as if the x is fully evaluated before y
+ ErrorEval firstXerr = null;
+ ErrorEval firstYerr = null;
+ boolean accumlatedSome = false;
+ double result = 0.0;
+
+ for (int i = 0; i < size; i++) {
+ ValueEval vx = x.getItem(i);
+ ValueEval vy = y.getItem(i);
+ if (vx instanceof ErrorEval) {
+ if (firstXerr == null) {
+ firstXerr = (ErrorEval) vx;
+ continue;
+ }
}
- }
- for (int i = 0; i < yops.length; i++) {
- Eval eval = yops[i];
- if (eval instanceof ErrorEval) {
- throw new EvaluationException((ErrorEval) eval);
+ if (vy instanceof ErrorEval) {
+ if (firstYerr == null) {
+ firstYerr = (ErrorEval) vy;
+ continue;
+ }
+ }
+ // only count pairs if both elements are numbers
+ if (vx instanceof NumberEval && vy instanceof NumberEval) {
+ accumlatedSome = true;
+ NumberEval nx = (NumberEval) vx;
+ NumberEval ny = (NumberEval) vy;
+ result += acc.accumulate(nx.getNumberValue(), ny.getNumberValue());
+ } else {
+ // all other combinations of value types are silently ignored
}
}
-
- double[] xResult = new double[nArrayItems];
- double[] yResult = new double[nArrayItems];
-
- int count = 0;
-
- for (int i=0, iSize=nArrayItems; i<iSize; i++) {
- Eval xEval = xops[i];
- Eval yEval = yops[i];
-
- if (isNumberEval(xEval) && isNumberEval(yEval)) {
- xResult[count] = getDoubleValue(xEval);
- yResult[count] = getDoubleValue(yEval);
- if (Double.isNaN(xResult[count]) || Double.isNaN(xResult[count])) {
- throw new EvaluationException(ErrorEval.NUM_ERROR);
- }
- count++;
- }
- }
-
- return new double[][] {
- trimToSize(xResult, count),
- trimToSize(yResult, count),
- };
- }
-
- private static double[][] getValues(Eval argX, Eval argY) throws EvaluationException {
-
- if (argX instanceof ErrorEval) {
- throw new EvaluationException((ErrorEval) argX);
- }
- if (argY instanceof ErrorEval) {
- throw new EvaluationException((ErrorEval) argY);
- }
-
- Eval[] xEvals;
- Eval[] yEvals;
- if (argX instanceof AreaEval) {
- AreaEval ae = (AreaEval) argX;
- xEvals = ae.getValues();
- } else {
- xEvals = new Eval[] { argX, };
- }
-
- if (argY instanceof AreaEval) {
- AreaEval ae = (AreaEval) argY;
- yEvals = ae.getValues();
- } else {
- yEvals = new Eval[] { argY, };
- }
-
- return getNumberArray(xEvals, yEvals);
- }
-
- private static double[] trimToSize(double[] arr, int len) {
- double[] tarr = arr;
- if (arr.length > len) {
- tarr = new double[len];
- System.arraycopy(arr, 0, tarr, 0, len);
- }
- return tarr;
- }
-
- private static boolean isNumberEval(Eval eval) {
- boolean retval = false;
-
- if (eval instanceof NumberEval) {
- retval = true;
- }
- else if (eval instanceof RefEval) {
- RefEval re = (RefEval) eval;
- ValueEval ve = re.getInnerValueEval();
- retval = (ve instanceof NumberEval);
- }
-
- return retval;
- }
-
- private static double getDoubleValue(Eval eval) {
- double retval = 0;
- if (eval instanceof NumberEval) {
- NumberEval ne = (NumberEval) eval;
- retval = ne.getNumberValue();
- }
- else if (eval instanceof RefEval) {
- RefEval re = (RefEval) eval;
- ValueEval ve = re.getInnerValueEval();
- retval = (ve instanceof NumberEval)
- ? ((NumberEval) ve).getNumberValue()
- : Double.NaN;
- }
- else if (eval instanceof ErrorEval) {
- retval = Double.NaN;
- }
- return retval;
- }
+ if (firstXerr != null) {
+ throw new EvaluationException(firstXerr);
+ }
+ if (firstYerr != null) {
+ throw new EvaluationException(firstYerr);
+ }
+ if (!accumlatedSome) {
+ throw new EvaluationException(ErrorEval.DIV_ZERO);
+ }
+ return result;
+ }
+
+ private static ValueVector createValueVector(Eval arg) throws EvaluationException {
+ if (arg instanceof ErrorEval) {
+ throw new EvaluationException((ErrorEval) arg);
+ }
+ if (arg instanceof AreaEval) {
+ return new AreaValueArray((AreaEval) arg);
+ }
+ if (arg instanceof RefEval) {
+ return new RefValueArray((RefEval) arg);
+ }
+ if (arg instanceof ValueEval) {
+ return new SingleCellValueArray((ValueEval) arg);
+ }
+ throw new RuntimeException("Unexpected eval class (" + arg.getClass().getName() + ")");
+ }
}
diff --git a/src/java/org/apache/poi/hssf/usermodel/HSSFFormulaEvaluator.java b/src/java/org/apache/poi/hssf/usermodel/HSSFFormulaEvaluator.java
index 97e605928d..4fb31606ea 100644
--- a/src/java/org/apache/poi/hssf/usermodel/HSSFFormulaEvaluator.java
+++ b/src/java/org/apache/poi/hssf/usermodel/HSSFFormulaEvaluator.java
@@ -43,19 +43,11 @@ public class HSSFFormulaEvaluator extends FormulaEvaluator {
return new FormulaParser(formula, workbook);
}
-
/**
* debug method
- *
- * @param formula
- * @param sheet
- * @param workbook
*/
void inspectPtgs(String formula) {
- HSSFWorkbook hssfWb = (HSSFWorkbook)_workbook;
- FormulaParser fp = new FormulaParser(formula, hssfWb);
- fp.parse();
- Ptg[] ptgs = fp.getRPNPtg();
+ Ptg[] ptgs = FormulaParser.parse(formula, _workbook);
System.out.println("<ptg-group>");
for (int i = 0, iSize = ptgs.length; i < iSize; i++) {
System.out.println("<ptg>");
diff --git a/src/java/org/apache/poi/hssf/usermodel/HSSFSheet.java b/src/java/org/apache/poi/hssf/usermodel/HSSFSheet.java
index 280284439b..6670b20414 100644
--- a/src/java/org/apache/poi/hssf/usermodel/HSSFSheet.java
+++ b/src/java/org/apache/poi/hssf/usermodel/HSSFSheet.java
@@ -35,17 +35,11 @@ import org.apache.poi.hssf.model.FormulaParser;
import org.apache.poi.hssf.model.Sheet;
import org.apache.poi.hssf.model.Workbook;
import org.apache.poi.hssf.record.CellValueRecordInterface;
-import org.apache.poi.hssf.record.CFRuleRecord;
-import org.apache.poi.hssf.record.DVALRecord;
import org.apache.poi.hssf.record.DVRecord;
-import org.apache.poi.hssf.record.EOFRecord;
import org.apache.poi.hssf.record.EscherAggregate;
-import org.apache.poi.hssf.record.HCenterRecord;
-import org.apache.poi.hssf.record.PageBreakRecord;
import org.apache.poi.hssf.record.Record;
import org.apache.poi.hssf.record.RowRecord;
import org.apache.poi.hssf.record.SCLRecord;
-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.hssf.record.aggregates.DataValidityTable;
@@ -385,6 +379,22 @@ public class HSSFSheet implements org.apache.poi.ss.usermodel.Sheet
DVRecord dvRecord = dataValidation.createDVRecord(workbook);
dvt.addDataValidation(dvRecord);
}
+
+ /**
+ * Get the DVRecords objects that are associated to this sheet
+ * @return a list of DVRecord instances
+ */
+ public List getDVRecords() {
+ List dvRecords = new ArrayList();
+ List records = sheet.getRecords();
+
+ for(int index=0; index<records.size(); index++) {
+ if(records.get(index) instanceof DVRecord) {
+ dvRecords.add(records.get(index));
+ }
+ }
+ return dvRecords;
+ }
/**
@@ -1273,11 +1283,9 @@ public class HSSFSheet implements org.apache.poi.ss.usermodel.Sheet
// Since it's a formula cell, process the
// formula string, and look to see if
// it contains any references
- FormulaParser fp = new FormulaParser(c.getCellFormula(), workbook);
- fp.parse();
// Look for references, and update if needed
- Ptg[] ptgs = fp.getRPNPtg();
+ Ptg[] ptgs = FormulaParser.parse(c.getCellFormula(), workbook);
boolean changed = false;
for(int i=0; i<ptgs.length; i++) {
if(ptgs[i] instanceof RefPtg) {
@@ -1294,7 +1302,7 @@ public class HSSFSheet implements org.apache.poi.ss.usermodel.Sheet
// re-create the formula string
if(changed) {
c.setCellFormula(
- fp.toFormulaString(ptgs)
+ FormulaParser.toFormulaString(workbook, ptgs)
);
}
}
diff --git a/src/java/org/apache/poi/hssf/usermodel/HSSFWorkbook.java b/src/java/org/apache/poi/hssf/usermodel/HSSFWorkbook.java
index eb1546ade9..801b298783 100644
--- a/src/java/org/apache/poi/hssf/usermodel/HSSFWorkbook.java
+++ b/src/java/org/apache/poi/hssf/usermodel/HSSFWorkbook.java
@@ -931,35 +931,17 @@ public class HSSFWorkbook extends POIDocument implements org.apache.poi.ss.userm
Stack ptgs = new Stack();
if (settingRowAndColumn) {
- final int exprsSize = 2 * 11 + 1; // Area3DPtg.SIZE + UnionPtg.SIZE
+ final int exprsSize = 2 * 11 + 1; // 2 * Area3DPtg.SIZE + UnionPtg.SIZE
ptgs.add(new MemFuncPtg(exprsSize));
}
- if (startColumn >= 0)
- {
- Area3DPtg colArea = new Area3DPtg();
- colArea.setExternSheetIndex(externSheetIndex);
- colArea.setFirstColumn((short)startColumn);
- colArea.setLastColumn((short)endColumn);
- colArea.setFirstRow(0);
- colArea.setLastRow(MAX_ROW);
- colArea.setFirstColRelative(false);
- colArea.setLastColRelative(false);
- colArea.setFirstRowRelative(false);
- colArea.setLastRowRelative(false);
+ if (startColumn >= 0) {
+ Area3DPtg colArea = new Area3DPtg(0, MAX_ROW, startColumn, endColumn,
+ false, false, false, false, externSheetIndex);
ptgs.add(colArea);
}
- if (startRow >= 0)
- {
- Area3DPtg rowArea = new Area3DPtg();
- rowArea.setExternSheetIndex(externSheetIndex);
- rowArea.setFirstColumn((short)0);
- rowArea.setLastColumn(MAX_COLUMN);
- rowArea.setFirstRow(startRow);
- rowArea.setLastRow(endRow);
- rowArea.setFirstColRelative(false);
- rowArea.setLastColRelative(false);
- rowArea.setFirstRowRelative(false);
- rowArea.setLastRowRelative(false);
+ if (startRow >= 0) {
+ Area3DPtg rowArea = new Area3DPtg(startRow, endRow, 0, MAX_COLUMN,
+ false, false, false, false, externSheetIndex);
ptgs.add(rowArea);
}
if (settingRowAndColumn)
diff --git a/src/java/org/apache/poi/hssf/util/AreaReference.java b/src/java/org/apache/poi/hssf/util/AreaReference.java
index a10b9976aa..d6575642ee 100644
--- a/src/java/org/apache/poi/hssf/util/AreaReference.java
+++ b/src/java/org/apache/poi/hssf/util/AreaReference.java
@@ -17,293 +17,21 @@
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 */
- private static final char SHEET_NAME_DELIMITER = '!';
- /** The character (:) that separates the two cell references in a multi-cell area reference */
- private static final char CELL_DELIMITER = ':';
- /** The character (') used to quote sheet names when they contain special characters */
- private static final char SPECIAL_NAME_DELIMITER = '\'';
-
- private final CellReference _firstCell;
- private final CellReference _lastCell;
- private final boolean _isSingleCell;
+public final class AreaReference extends org.apache.poi.ss.util.AreaReference {
/**
* Create an area ref from a string representation. Sheet names containing special characters should be
* delimited and escaped as per normal syntax rules for formulas.<br/>
* The area reference must be contiguous (i.e. represent a single rectangle, not a union of rectangles)
*/
public AreaReference(String reference) {
- if(! isContiguous(reference)) {
- throw new IllegalArgumentException(
- "References passed to the AreaReference must be contiguous, " +
- "use generateContiguous(ref) if you have non-contiguous references");
- }
-
- String[] parts = separateAreaRefs(reference);
-
- // 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";
- }
-
- _firstCell = new CellReference(parts[0]);
-
- if(parts.length == 2) {
- _lastCell = new CellReference(parts[1]);
- _isSingleCell = false;
- } else {
- _lastCell = _firstCell;
- _isSingleCell = true;
- }
+ super(reference);
}
/**
* Creates an area ref from a pair of Cell References.
*/
public AreaReference(CellReference topLeft, CellReference botRight) {
- _firstCell = topLeft;
- _lastCell = botRight;
- _isSingleCell = false;
- }
-
- /**
- * Is the reference for a contiguous (i.e.
- * unbroken) area, or is it made up of
- * several different parts?
- * (If it is, you will need to call
- * ....
- */
- public static boolean isContiguous(String reference) {
- if(reference.indexOf(',') == -1) {
- return true;
- }
- return false;
- }
-
- /**
- * Is the reference for a whole-column reference,
- * 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;
- }
- public boolean isWholeColumnReference() {
- return isWholeColumnReference(_firstCell, _lastCell);
- }
-
- /**
- * Takes a non-contiguous area reference, and
- * returns an array of contiguous area references.
- */
- public static AreaReference[] generateContiguous(String reference) {
- ArrayList refs = new ArrayList();
- StringTokenizer st = new StringTokenizer(reference, ",");
- while(st.hasMoreTokens()) {
- refs.add(
- new AreaReference(st.nextToken())
- );
- }
- return (AreaReference[])refs.toArray(new AreaReference[refs.size()]);
- }
-
- /**
- * @return <code>false</code> if this area reference involves more than one cell
- */
- public boolean isSingleCell() {
- return _isSingleCell;
- }
-
- /**
- * @return the first cell reference which defines this area. Usually this cell is in the upper
- * left corner of the area (but this is not a requirement).
- */
- public CellReference getFirstCell() {
- return _firstCell;
- }
-
- /**
- * Note - if this area reference refers to a single cell, the return value of this method will
- * be identical to that of <tt>getFirstCell()</tt>
- * @return the second cell reference which defines this area. For multi-cell areas, this is
- * cell diagonally opposite the 'first cell'. Usually this cell is in the lower right corner
- * of the area (but this is not a requirement).
- */
- public CellReference getLastCell() {
- return _lastCell;
- }
- /**
- * 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, };
- }
-
- // 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());
- 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()]);
- }
-
- /**
- * Example return values:
- * <table border="0" cellpadding="1" cellspacing="0" summary="Example return values">
- * <tr><th align='left'>Result</th><th align='left'>Comment</th></tr>
- * <tr><td>A1:A1</td><td>Single cell area reference without sheet</td></tr>
- * <tr><td>A1:$C$1</td><td>Multi-cell area reference without sheet</td></tr>
- * <tr><td>Sheet1!A$1:B4</td><td>Standard sheet name</td></tr>
- * <tr><td>'O''Brien''s Sales'!B5:C6'&nbsp;</td><td>Sheet name with special characters</td></tr>
- * </table>
- * @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());
- }
-
- StringBuffer sb = new StringBuffer(32);
- sb.append(_firstCell.formatAsString());
- if(!_isSingleCell) {
- sb.append(CELL_DELIMITER);
- if(_lastCell.getSheetName() == null) {
- sb.append(_lastCell.formatAsString());
- } else {
- // don't want to include the sheet name twice
- _lastCell.appendCellReference(sb);
- }
- }
- 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(" [");
- sb.append(formatAsString());
- sb.append("]");
- return sb.toString();
- }
-
- /**
- * Separates Area refs in two parts and returns them as separate elements in a String array,
- * each qualified with the sheet name (if present)
- *
- * @return array with one or two elements. never <code>null</code>
- */
- private static String[] separateAreaRefs(String reference) {
- // TODO - refactor cell reference parsing logic to one place.
- // Current known incarnations:
- // FormulaParser.GetName()
- // CellReference.separateRefParts()
- // AreaReference.separateAreaRefs() (here)
- // SheetNameFormatter.format() (inverse)
-
-
- int len = reference.length();
- int delimiterPos = -1;
- boolean insideDelimitedName = false;
- for(int i=0; i<len; i++) {
- switch(reference.charAt(i)) {
- case CELL_DELIMITER:
- if(!insideDelimitedName) {
- if(delimiterPos >=0) {
- throw new IllegalArgumentException("More than one cell delimiter '"
- + CELL_DELIMITER + "' appears in area reference '" + reference + "'");
- }
- delimiterPos = i;
- }
- default:
- continue;
- case SPECIAL_NAME_DELIMITER:
- // fall through
- }
- if(!insideDelimitedName) {
- insideDelimitedName = true;
- continue;
- }
-
- if(i >= len-1) {
- // reference ends with the delimited name.
- // Assume names like: "Sheet1!'A1'" are never legal.
- throw new IllegalArgumentException("Area reference '" + reference
- + "' ends with special name delimiter '" + SPECIAL_NAME_DELIMITER + "'");
- }
- if(reference.charAt(i+1) == SPECIAL_NAME_DELIMITER) {
- // two consecutive quotes is the escape sequence for a single one
- i++; // skip this and keep parsing the special name
- } else {
- // this is the end of the delimited name
- insideDelimitedName = false;
- }
- }
- if(delimiterPos < 0) {
- return new String[] { reference, };
- }
-
- String partA = reference.substring(0, delimiterPos);
- String partB = reference.substring(delimiterPos+1);
- if(partB.indexOf(SHEET_NAME_DELIMITER) >=0) {
- // TODO - are references like "Sheet1!A1:Sheet1:B2" ever valid?
- // FormulaParser has code to handle that.
-
- throw new RuntimeException("Unexpected " + SHEET_NAME_DELIMITER
- + " in second cell reference of '" + reference + "'");
- }
-
- int plingPos = partA.lastIndexOf(SHEET_NAME_DELIMITER);
- if(plingPos < 0) {
- return new String [] { partA, partB, };
- }
-
- String sheetName = partA.substring(0, plingPos + 1); // +1 to include delimiter
-
- return new String [] { partA, sheetName + partB, };
+ super(topLeft, botRight);
}
-} \ No newline at end of file
+}
diff --git a/src/java/org/apache/poi/ss/usermodel/FormulaEvaluator.java b/src/java/org/apache/poi/ss/usermodel/FormulaEvaluator.java
index 74e92b0a8d..aa71c68c54 100644
--- a/src/java/org/apache/poi/ss/usermodel/FormulaEvaluator.java
+++ b/src/java/org/apache/poi/ss/usermodel/FormulaEvaluator.java
@@ -1,26 +1,23 @@
-/*
-* 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.
-*/
+/* ====================================================================
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+==================================================================== */
package org.apache.poi.ss.usermodel;
-import java.lang.reflect.Constructor;
-import java.util.HashMap;
import java.util.Iterator;
-import java.util.Map;
import java.util.Stack;
import org.apache.poi.hssf.model.FormulaParser;
@@ -28,6 +25,7 @@ import org.apache.poi.hssf.record.formula.Area3DPtg;
import org.apache.poi.hssf.record.formula.AreaPtg;
import org.apache.poi.hssf.record.formula.BoolPtg;
import org.apache.poi.hssf.record.formula.ControlPtg;
+import org.apache.poi.hssf.record.formula.ErrPtg;
import org.apache.poi.hssf.record.formula.IntPtg;
import org.apache.poi.hssf.record.formula.MemErrPtg;
import org.apache.poi.hssf.record.formula.MissingArgPtg;
@@ -41,77 +39,51 @@ import org.apache.poi.hssf.record.formula.RefPtg;
import org.apache.poi.hssf.record.formula.StringPtg;
import org.apache.poi.hssf.record.formula.UnionPtg;
import org.apache.poi.hssf.record.formula.UnknownPtg;
-import org.apache.poi.hssf.record.formula.eval.Area2DEval;
-import org.apache.poi.hssf.record.formula.eval.Area3DEval;
import org.apache.poi.hssf.record.formula.eval.AreaEval;
import org.apache.poi.hssf.record.formula.eval.BlankEval;
import org.apache.poi.hssf.record.formula.eval.BoolEval;
import org.apache.poi.hssf.record.formula.eval.ErrorEval;
import org.apache.poi.hssf.record.formula.eval.Eval;
import org.apache.poi.hssf.record.formula.eval.FunctionEval;
+import org.apache.poi.hssf.record.formula.eval.LazyAreaEval;
+import org.apache.poi.hssf.record.formula.eval.LazyRefEval;
import org.apache.poi.hssf.record.formula.eval.NameEval;
import org.apache.poi.hssf.record.formula.eval.NameXEval;
import org.apache.poi.hssf.record.formula.eval.NumberEval;
import org.apache.poi.hssf.record.formula.eval.OperationEval;
-import org.apache.poi.hssf.record.formula.eval.Ref2DEval;
-import org.apache.poi.hssf.record.formula.eval.Ref3DEval;
import org.apache.poi.hssf.record.formula.eval.RefEval;
import org.apache.poi.hssf.record.formula.eval.StringEval;
import org.apache.poi.hssf.record.formula.eval.ValueEval;
-import org.apache.poi.hssf.usermodel.HSSFFormulaEvaluator;
/**
* @author Amol S. Deshmukh &lt; amolweb at ya hoo dot com &gt;
- *
+ *
*/
public class FormulaEvaluator {
-
- // params to lookup the right constructor using reflection
- private static final Class[] VALUE_CONTRUCTOR_CLASS_ARRAY = new Class[] { Ptg.class };
- private static final Class[] AREA3D_CONSTRUCTOR_CLASS_ARRAY = new Class[] { Ptg.class, ValueEval[].class };
-
- private static final Class[] REFERENCE_CONSTRUCTOR_CLASS_ARRAY = new Class[] { Ptg.class, ValueEval.class };
-
- private static final Class[] REF3D_CONSTRUCTOR_CLASS_ARRAY = new Class[] { Ptg.class, ValueEval.class };
-
- // Maps for mapping *Eval to *Ptg
- private static final Map VALUE_EVALS_MAP = new HashMap();
-
- /*
- * Following is the mapping between the Ptg tokens returned
- * by the FormulaParser and the *Eval classes that are used
- * by the FormulaEvaluator
- */
- static {
- VALUE_EVALS_MAP.put(BoolPtg.class, BoolEval.class);
- VALUE_EVALS_MAP.put(IntPtg.class, NumberEval.class);
- VALUE_EVALS_MAP.put(NumberPtg.class, NumberEval.class);
- VALUE_EVALS_MAP.put(StringPtg.class, StringEval.class);
-
- }
-
-
protected Sheet _sheet;
protected Workbook _workbook;
-
+
public FormulaEvaluator(Sheet sheet, Workbook workbook) {
- this._sheet = sheet;
- this._workbook = workbook;
+ _sheet = sheet;
+ _workbook = workbook;
}
-
+
/**
* Does nothing
* @deprecated (Aug 2008) - not needed, since the current row can be derived from the cell
*/
- public void setCurrentRow(Row row) {}
+ public void setCurrentRow(Row row) {
+ // do nothing
+ }
+
/**
* If cell contains a formula, the formula is evaluated and returned,
* else the CellValue simply copies the appropriate cell value from
* the cell and also its cell type. This method should be preferred over
* evaluateInCell() when the call should not modify the contents of the
- * original cell.
+ * original cell.
* @param cell
*/
public CellValue evaluate(Cell cell) {
@@ -144,25 +116,25 @@ public class FormulaEvaluator {
}
return retval;
}
-
-
+
+
/**
* If cell contains formula, it evaluates the formula,
* and saves the result of the formula. The cell
* remains as a formula cell.
* Else if cell does not contain formula, this method leaves
- * the cell unchanged.
+ * the cell unchanged.
* Note that the type of the formula result is returned,
* so you know what kind of value is also stored with
- * the formula.
+ * the formula.
* <pre>
* int evaluatedCellType = evaluator.evaluateFormulaCell(cell);
* </pre>
* Be aware that your cell will hold both the formula,
* and the result. If you want the cell replaced with
- * the result of the formula, use {@link #evaluateInCell(HSSFCell)}
+ * the result of the formula, use {@link #evaluateInCell(Cell)}
* @param cell The cell to evaluate
- * @return The type of the formula result (the cell's type remains as HSSFCell.CELL_TYPE_FORMULA however)
+ * @return The type of the formula result (the cell's type remains as Cell.CELL_TYPE_FORMULA however)
*/
public int evaluateFormulaCell(Cell cell) {
if (cell != null) {
@@ -192,21 +164,21 @@ public class FormulaEvaluator {
}
return -1;
}
-
+
/**
* If cell contains formula, it evaluates the formula, and
* puts the formula result back into the cell, in place
* of the old formula.
* Else if cell does not contain formula, this method leaves
- * the cell unchanged.
- * Note that the same instance of HSSFCell is returned to
+ * the cell unchanged.
+ * Note that the same instance of Cell is returned to
* allow chained calls like:
* <pre>
* int evaluatedCellType = evaluator.evaluateInCell(cell).getCellType();
* </pre>
* Be aware that your cell value will be changed to hold the
* result of the formula. If you simply want the formula
- * value computed for you, use {@link #evaluateFormulaCell(HSSFCell)}
+ * value computed for you, use {@link #evaluateFormulaCell(Cell)}
* @param cell
*/
public Cell evaluateInCell(Cell cell) {
@@ -239,7 +211,7 @@ public class FormulaEvaluator {
}
return cell;
}
-
+
/**
* Loops over all cells in all sheets of the supplied
* workbook.
@@ -248,32 +220,32 @@ public class FormulaEvaluator {
* remain as formula cells.
* For cells that do not contain formulas, no changes
* are made.
- * This is a helpful wrapper around looping over all
+ * This is a helpful wrapper around looping over all
* cells, and calling evaluateFormulaCell on each one.
*/
- public static void evaluateAllFormulaCells(Workbook wb) {
- for(int i=0; i<wb.getNumberOfSheets(); i++) {
- Sheet sheet = wb.getSheetAt(i);
- FormulaEvaluator evaluator = new FormulaEvaluator(sheet, wb);
-
- for (Iterator rit = sheet.rowIterator(); rit.hasNext();) {
- Row r = (Row)rit.next();
-
- for (Iterator cit = r.cellIterator(); cit.hasNext();) {
- Cell c = (Cell)cit.next();
- if (c.getCellType() == Cell.CELL_TYPE_FORMULA)
- evaluator.evaluateFormulaCell(c);
- }
- }
- }
- }
-
-
+ public static void evaluateAllFormulaCells(Workbook wb) {
+ for(int i=0; i<wb.getNumberOfSheets(); i++) {
+ Sheet sheet = wb.getSheetAt(i);
+ FormulaEvaluator evaluator = new FormulaEvaluator(sheet, wb);
+
+ for (Iterator rit = sheet.rowIterator(); rit.hasNext();) {
+ Row r = (Row)rit.next();
+
+ for (Iterator cit = r.cellIterator(); cit.hasNext();) {
+ Cell c = (Cell)cit.next();
+ if (c.getCellType() == Cell.CELL_TYPE_FORMULA)
+ evaluator.evaluateFormulaCell(c);
+ }
+ }
+ }
+ }
+
+
/**
* Returns a CellValue wrapper around the supplied ValueEval instance.
* @param eval
*/
- protected static CellValue getCellValueForEval(ValueEval eval, CreationHelper cHelper) {
+ private static CellValue getCellValueForEval(ValueEval eval, CreationHelper cHelper) {
CellValue retval = null;
if (eval != null) {
if (eval instanceof NumberEval) {
@@ -297,7 +269,7 @@ public class FormulaEvaluator {
else if (eval instanceof ErrorEval) {
retval = new CellValue(Cell.CELL_TYPE_ERROR, cHelper);
retval.setErrorValue((byte)((ErrorEval)eval).getErrorCode());
-// retval.setRichTextStringValue(new HSSFRichTextString("#An error occurred. check cell.getErrorCode()"));
+// retval.setRichTextStringValue(new RichTextString("#An error occurred. check cell.getErrorCode()"));
}
else {
retval = new CellValue(Cell.CELL_TYPE_ERROR, cHelper);
@@ -305,19 +277,19 @@ public class FormulaEvaluator {
}
return retval;
}
-
+
/**
- * Dev. Note: Internal evaluate must be passed only a formula cell
+ * Dev. Note: Internal evaluate must be passed only a formula cell
* else a runtime exception will be thrown somewhere inside the method.
* (Hence this is a private method.)
*/
private static ValueEval internalEvaluate(Cell srcCell, Sheet sheet, Workbook workbook) {
int srcRowNum = srcCell.getRowIndex();
short srcColNum = srcCell.getCellNum();
-
-
+
+
EvaluationCycleDetector tracker = EvaluationCycleDetectorManager.getTracker();
-
+
if(!tracker.startEvaluate(workbook, sheet, srcRowNum, srcColNum)) {
return ErrorEval.CIRCULAR_REF_ERROR;
}
@@ -327,8 +299,9 @@ public class FormulaEvaluator {
tracker.endEvaluate(workbook, sheet, srcRowNum, srcColNum);
}
}
- private static ValueEval evaluateCell(Workbook workbook, Sheet sheet,
+ private static ValueEval evaluateCell(Workbook workbook, Sheet sheet,
int srcRowNum, short srcColNum, String cellFormulaText) {
+
Ptg[] ptgs = FormulaParser.parse(cellFormulaText, workbook);
Stack stack = new Stack();
@@ -337,16 +310,16 @@ public class FormulaEvaluator {
// since we don't know how to handle these yet :(
Ptg ptg = ptgs[i];
if (ptg instanceof ControlPtg) {
- // skip Parentheses, Attr, etc
- continue;
- }
+ // skip Parentheses, Attr, etc
+ continue;
+ }
if (ptg instanceof MemErrPtg) { continue; }
if (ptg instanceof MissingArgPtg) { continue; }
- if (ptg instanceof NamePtg) {
+ if (ptg instanceof NamePtg) {
// named ranges, macro functions
NamePtg namePtg = (NamePtg) ptg;
stack.push(new NameEval(namePtg.getIndex()));
- continue;
+ continue;
}
if (ptg instanceof NameXPtg) {
NameXPtg nameXPtg = (NameXPtg) ptg;
@@ -354,7 +327,7 @@ public class FormulaEvaluator {
continue;
}
if (ptg instanceof UnknownPtg) { continue; }
-
+ Eval opResult;
if (ptg instanceof OperationPtg) {
OperationPtg optg = (OperationPtg) ptg;
@@ -370,42 +343,11 @@ public class FormulaEvaluator {
Eval p = (Eval) stack.pop();
ops[j] = p;
}
- Eval opresult = invokeOperation(operation, ops, srcRowNum, srcColNum, workbook, sheet);
- stack.push(opresult);
- }
- else if (ptg instanceof RefPtg) {
- RefPtg refPtg = (RefPtg) ptg;
- int colIx = refPtg.getColumn();
- int rowIx = refPtg.getRow();
- Row row = sheet.getRow(rowIx);
- Cell cell = (row != null) ? row.getCell(colIx) : null;
- stack.push(createRef2DEval(refPtg, cell, sheet, workbook));
- }
- else if (ptg instanceof Ref3DPtg) {
- Ref3DPtg refPtg = (Ref3DPtg) ptg;
- int colIx = refPtg.getColumn();
- int rowIx = refPtg.getRow();
- Sheet xsheet = workbook.getSheetAt(
- workbook.getSheetIndexFromExternSheetIndex(refPtg.getExternSheetIndex())
- );
- Row row = xsheet.getRow(rowIx);
- Cell cell = (row != null) ? row.getCell(colIx) : null;
- stack.push(createRef3DEval(refPtg, cell, xsheet, workbook));
- }
- else if (ptg instanceof AreaPtg) {
- AreaPtg ap = (AreaPtg) ptg;
- AreaEval ae = evaluateAreaPtg(sheet, workbook, ap);
- stack.push(ae);
- }
- else if (ptg instanceof Area3DPtg) {
- Area3DPtg a3dp = (Area3DPtg) ptg;
- AreaEval ae = evaluateArea3dPtg(workbook, a3dp);
- stack.push(ae);
- }
- else {
- Eval ptgEval = getEvalForPtg(ptg);
- stack.push(ptgEval);
+ opResult = invokeOperation(operation, ops, srcRowNum, srcColNum, workbook, sheet);
+ } else {
+ opResult = getEvalForPtg(ptg, sheet, workbook);
}
+ stack.push(opResult);
}
ValueEval value = ((ValueEval) stack.pop());
@@ -414,9 +356,9 @@ public class FormulaEvaluator {
}
value = dereferenceValue(value, srcRowNum, srcColNum);
if (value instanceof BlankEval) {
- // Note Excel behaviour here. A blank final final value is converted to zero.
+ // Note Excel behaviour here. A blank final final value is converted to zero.
return NumberEval.ZERO;
- // Formulas _never_ evaluate to blank. If a formula appears to have evaluated to
+ // Formulas _never_ evaluate to blank. If a formula appears to have evaluated to
// blank, the actual value is empty string. This can be verified with ISBLANK().
}
return value;
@@ -425,8 +367,8 @@ public class FormulaEvaluator {
/**
* Dereferences a single value from any AreaEval or RefEval evaluation result.
* If the supplied evaluationResult is just a plain value, it is returned as-is.
- * @return a <tt>NumberEval</tt>, <tt>StringEval</tt>, <tt>BoolEval</tt>,
- * <tt>BlankEval</tt> or <tt>ErrorEval</tt>. Never <code>null</code>.
+ * @return a <tt>NumberEval</tt>, <tt>StringEval</tt>, <tt>BoolEval</tt>,
+ * <tt>BlankEval</tt> or <tt>ErrorEval</tt>. Never <code>null</code>.
*/
private static ValueEval dereferenceValue(ValueEval evaluationResult, int srcRowNum, short srcColNum) {
if (evaluationResult instanceof RefEval) {
@@ -460,107 +402,48 @@ public class FormulaEvaluator {
}
return operation.evaluate(ops, srcRowNum, srcColNum);
}
-
- public static AreaEval evaluateAreaPtg(Sheet sheet, Workbook workbook, AreaPtg ap) {
- int row0 = ap.getFirstRow();
- int col0 = ap.getFirstColumn();
- int row1 = ap.getLastRow();
- int col1 = ap.getLastColumn();
-
- // If the last row is -1, then the
- // reference is for the rest of the column
- // (eg C:C)
- // TODO: Handle whole column ranges properly
- if(row1 == -1 && row0 >= 0) {
- row1 = (short)sheet.getLastRowNum();
- }
- ValueEval[] values = evalArea(workbook, sheet, row0, col0, row1, col1);
- return new Area2DEval(ap, values);
- }
-
- public static AreaEval evaluateArea3dPtg(Workbook workbook, Area3DPtg a3dp) {
- int row0 = a3dp.getFirstRow();
- int col0 = a3dp.getFirstColumn();
- int row1 = a3dp.getLastRow();
- int col1 = a3dp.getLastColumn();
- Sheet xsheet = workbook.getSheetAt(
- workbook.getSheetIndexFromExternSheetIndex(a3dp.getExternSheetIndex())
- );
-
- // If the last row is -1, then the
- // reference is for the rest of the column
- // (eg C:C)
- // TODO: Handle whole column ranges properly
- if(row1 == -1 && row0 >= 0) {
- row1 = (short)xsheet.getLastRowNum();
- }
-
- ValueEval[] values = evalArea(workbook, xsheet, row0, col0, row1, col1);
- return new Area3DEval(a3dp, values);
- }
-
- private static ValueEval[] evalArea(Workbook workbook, Sheet sheet,
- int row0, int col0, int row1, int col1) {
- ValueEval[] values = new ValueEval[(row1 - row0 + 1) * (col1 - col0 + 1)];
- for (int x = row0; sheet != null && x < row1 + 1; x++) {
- Row row = sheet.getRow(x);
- for (int y = col0; y < col1 + 1; y++) {
- ValueEval cellEval;
- if(row == null) {
- cellEval = BlankEval.INSTANCE;
- } else {
- cellEval = getEvalForCell(row.getCell(y), row, sheet, workbook);
- }
- values[(x - row0) * (col1 - col0 + 1) + (y - col0)] = cellEval;
- }
- }
- return values;
- }
/**
* returns an appropriate Eval impl instance for the Ptg. The Ptg must be
- * one of: Area3DPtg, AreaPtg, RefPtg, Ref3DPtg, IntPtg, NumberPtg,
+ * one of: Area3DPtg, AreaPtg, ReferencePtg, Ref3DPtg, IntPtg, NumberPtg,
* StringPtg, BoolPtg <br/>special Note: OperationPtg subtypes cannot be
* passed here!
- *
- * @param ptg
*/
- protected static Eval getEvalForPtg(Ptg ptg) {
- Eval retval = null;
-
- Class clazz = (Class) VALUE_EVALS_MAP.get(ptg.getClass());
- try {
- if (ptg instanceof Area3DPtg) {
- Constructor constructor = clazz.getConstructor(AREA3D_CONSTRUCTOR_CLASS_ARRAY);
- retval = (OperationEval) constructor.newInstance(new Ptg[] { ptg });
- }
- else if (ptg instanceof AreaPtg) {
- Constructor constructor = clazz.getConstructor(AREA3D_CONSTRUCTOR_CLASS_ARRAY);
- retval = (OperationEval) constructor.newInstance(new Ptg[] { ptg });
- }
- else if (ptg instanceof RefPtg) {
- Constructor constructor = clazz.getConstructor(REFERENCE_CONSTRUCTOR_CLASS_ARRAY);
- retval = (OperationEval) constructor.newInstance(new Ptg[] { ptg });
- }
- else if (ptg instanceof Ref3DPtg) {
- Constructor constructor = clazz.getConstructor(REF3D_CONSTRUCTOR_CLASS_ARRAY);
- retval = (OperationEval) constructor.newInstance(new Ptg[] { ptg });
- }
- else {
- if (ptg instanceof IntPtg || ptg instanceof NumberPtg || ptg instanceof StringPtg
- || ptg instanceof BoolPtg) {
- Constructor constructor = clazz.getConstructor(VALUE_CONTRUCTOR_CLASS_ARRAY);
- retval = (ValueEval) constructor.newInstance(new Ptg[] { ptg });
- }
- }
+ private static Eval getEvalForPtg(Ptg ptg, Sheet sheet, Workbook workbook) {
+ if (ptg instanceof RefPtg) {
+ return new LazyRefEval(((RefPtg) ptg), sheet, workbook);
}
- catch (Exception e) {
- throw new RuntimeException("Fatal Error: ", e);
+ if (ptg instanceof Ref3DPtg) {
+ Ref3DPtg refPtg = (Ref3DPtg) ptg;
+ Sheet xsheet = workbook.getSheetAt(workbook.getSheetIndexFromExternSheetIndex(refPtg.getExternSheetIndex()));
+ return new LazyRefEval(refPtg, xsheet, workbook);
+ }
+ if (ptg instanceof AreaPtg) {
+ return new LazyAreaEval(((AreaPtg) ptg), sheet, workbook);
+ }
+ if (ptg instanceof Area3DPtg) {
+ Area3DPtg a3dp = (Area3DPtg) ptg;
+ Sheet xsheet = workbook.getSheetAt(workbook.getSheetIndexFromExternSheetIndex(a3dp.getExternSheetIndex()));
+ return new LazyAreaEval(a3dp, xsheet, workbook);
}
- return retval;
+ if (ptg instanceof IntPtg) {
+ return new NumberEval(((IntPtg)ptg).getValue());
+ }
+ if (ptg instanceof NumberPtg) {
+ return new NumberEval(((NumberPtg)ptg).getValue());
+ }
+ if (ptg instanceof StringPtg) {
+ return new StringEval(((StringPtg) ptg).getValue());
+ }
+ if (ptg instanceof BoolPtg) {
+ return BoolEval.valueOf(((BoolPtg) ptg).getValue());
+ }
+ if (ptg instanceof ErrPtg) {
+ return ErrorEval.valueOf(((ErrPtg) ptg).getErrorCode());
+ }
+ throw new RuntimeException("Unexpected ptg class (" + ptg.getClass().getName() + ")");
}
-
/**
* Given a cell, find its type and from that create an appropriate ValueEval
* impl instance and return that. Since the cell could be an external
@@ -570,7 +453,7 @@ public class FormulaEvaluator {
* @param sheet
* @param workbook
*/
- protected static ValueEval getEvalForCell(Cell cell, Row row, Sheet sheet, Workbook workbook) {
+ public static ValueEval getEvalForCell(Cell cell, Sheet sheet, Workbook workbook) {
if (cell == null) {
return BlankEval.INSTANCE;
@@ -593,73 +476,21 @@ public class FormulaEvaluator {
}
/**
- * Creates a Ref2DEval for RefPtg.
- * Non existent cells are treated as RefEvals containing BlankEval.
- */
- private static Ref2DEval createRef2DEval(RefPtg ptg, Cell cell,
- Sheet sheet, Workbook workbook) {
- if (cell == null) {
- return new Ref2DEval(ptg, BlankEval.INSTANCE);
- }
-
- switch (cell.getCellType()) {
- case Cell.CELL_TYPE_NUMERIC:
- return new Ref2DEval(ptg, new NumberEval(cell.getNumericCellValue()));
- case Cell.CELL_TYPE_STRING:
- return new Ref2DEval(ptg, new StringEval(cell.getRichStringCellValue().getString()));
- case Cell.CELL_TYPE_FORMULA:
- return new Ref2DEval(ptg, internalEvaluate(cell, sheet, workbook));
- case Cell.CELL_TYPE_BOOLEAN:
- return new Ref2DEval(ptg, BoolEval.valueOf(cell.getBooleanCellValue()));
- case Cell.CELL_TYPE_BLANK:
- return new Ref2DEval(ptg, BlankEval.INSTANCE);
- case Cell.CELL_TYPE_ERROR:
- return new Ref2DEval(ptg, ErrorEval.valueOf(cell.getErrorCellValue()));
- }
- throw new RuntimeException("Unexpected cell type (" + cell.getCellType() + ")");
- }
-
- /**
- * create a Ref3DEval for Ref3DPtg.
- */
- private static Ref3DEval createRef3DEval(Ref3DPtg ptg, Cell cell,
- Sheet sheet, Workbook workbook) {
- if (cell == null) {
- return new Ref3DEval(ptg, BlankEval.INSTANCE);
- }
- switch (cell.getCellType()) {
- case Cell.CELL_TYPE_NUMERIC:
- return new Ref3DEval(ptg, new NumberEval(cell.getNumericCellValue()));
- case Cell.CELL_TYPE_STRING:
- return new Ref3DEval(ptg, new StringEval(cell.getRichStringCellValue().getString()));
- case Cell.CELL_TYPE_FORMULA:
- return new Ref3DEval(ptg, internalEvaluate(cell, sheet, workbook));
- case Cell.CELL_TYPE_BOOLEAN:
- return new Ref3DEval(ptg, BoolEval.valueOf(cell.getBooleanCellValue()));
- case Cell.CELL_TYPE_BLANK:
- return new Ref3DEval(ptg, BlankEval.INSTANCE);
- case Cell.CELL_TYPE_ERROR:
- return new Ref3DEval(ptg, ErrorEval.valueOf(cell.getErrorCellValue()));
- }
- throw new RuntimeException("Unexpected cell type (" + cell.getCellType() + ")");
- }
-
- /**
- * Mimics the 'data view' of a cell. This allows formula evaluator
+ * Mimics the 'data view' of a cell. This allows formula evaluator
* to return a CellValue instead of precasting the value to String
* or Number or boolean type.
* @author Amol S. Deshmukh &lt; amolweb at ya hoo dot com &gt;
*/
public static class CellValue {
- private CreationHelper creationHelper;
+ private CreationHelper creationHelper;
private int cellType;
private RichTextString richTextStringValue;
private double numberValue;
private boolean booleanValue;
private byte errorValue;
-
+
/**
- * CellType should be one of the types defined in HSSFCell
+ * CellType should be one of the types defined in Cell
* @param cellType
*/
public CellValue(int cellType, CreationHelper creationHelper) {
@@ -705,8 +536,8 @@ public class FormulaEvaluator {
* @deprecated
*/
public void setStringValue(String stringValue) {
- this.richTextStringValue =
- creationHelper.createRichTextString(stringValue);
+ this.richTextStringValue =
+ creationHelper.createRichTextString(stringValue);
}
/**
* @return Returns the cellType.
diff --git a/src/java/org/apache/poi/ss/util/AreaReference.java b/src/java/org/apache/poi/ss/util/AreaReference.java
new file mode 100644
index 0000000000..b5e06b9af9
--- /dev/null
+++ b/src/java/org/apache/poi/ss/util/AreaReference.java
@@ -0,0 +1,296 @@
+/* ====================================================================
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+==================================================================== */
+
+package org.apache.poi.ss.util;
+
+import java.util.ArrayList;
+import java.util.StringTokenizer;
+
+public class AreaReference {
+
+ /** The character (!) that separates sheet names from cell references */
+ private static final char SHEET_NAME_DELIMITER = '!';
+ /** The character (:) that separates the two cell references in a multi-cell area reference */
+ private static final char CELL_DELIMITER = ':';
+ /** The character (') used to quote sheet names when they contain special characters */
+ private static final char SPECIAL_NAME_DELIMITER = '\'';
+
+ private final CellReference _firstCell;
+ private final CellReference _lastCell;
+ private final boolean _isSingleCell;
+
+ /**
+ * Create an area ref from a string representation. Sheet names containing special characters should be
+ * delimited and escaped as per normal syntax rules for formulas.<br/>
+ * The area reference must be contiguous (i.e. represent a single rectangle, not a union of rectangles)
+ */
+ public AreaReference(String reference) {
+ if(! isContiguous(reference)) {
+ throw new IllegalArgumentException(
+ "References passed to the AreaReference must be contiguous, " +
+ "use generateContiguous(ref) if you have non-contiguous references");
+ }
+
+ String[] parts = separateAreaRefs(reference);
+
+ // 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";
+ }
+
+ _firstCell = new CellReference(parts[0]);
+
+ if(parts.length == 2) {
+ _lastCell = new CellReference(parts[1]);
+ _isSingleCell = false;
+ } else {
+ _lastCell = _firstCell;
+ _isSingleCell = true;
+ }
+ }
+
+ /**
+ * Creates an area ref from a pair of Cell References.
+ */
+ public AreaReference(CellReference topLeft, CellReference botRight) {
+ _firstCell = topLeft;
+ _lastCell = botRight;
+ _isSingleCell = false;
+ }
+
+ /**
+ * Is the reference for a contiguous (i.e.
+ * unbroken) area, or is it made up of
+ * several different parts?
+ * (If it is, you will need to call
+ * ....
+ */
+ public static boolean isContiguous(String reference) {
+ if(reference.indexOf(',') == -1) {
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Is the reference for a whole-column reference,
+ * 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;
+ }
+ public boolean isWholeColumnReference() {
+ return isWholeColumnReference(_firstCell, _lastCell);
+ }
+
+ /**
+ * Takes a non-contiguous area reference, and
+ * returns an array of contiguous area references.
+ */
+ public static AreaReference[] generateContiguous(String reference) {
+ ArrayList refs = new ArrayList();
+ StringTokenizer st = new StringTokenizer(reference, ",");
+ while(st.hasMoreTokens()) {
+ refs.add(
+ new AreaReference(st.nextToken())
+ );
+ }
+ return (AreaReference[])refs.toArray(new AreaReference[refs.size()]);
+ }
+
+ /**
+ * @return <code>false</code> if this area reference involves more than one cell
+ */
+ public boolean isSingleCell() {
+ return _isSingleCell;
+ }
+
+ /**
+ * @return the first cell reference which defines this area. Usually this cell is in the upper
+ * left corner of the area (but this is not a requirement).
+ */
+ public CellReference getFirstCell() {
+ return _firstCell;
+ }
+
+ /**
+ * Note - if this area reference refers to a single cell, the return value of this method will
+ * be identical to that of <tt>getFirstCell()</tt>
+ * @return the second cell reference which defines this area. For multi-cell areas, this is
+ * cell diagonally opposite the 'first cell'. Usually this cell is in the lower right corner
+ * of the area (but this is not a requirement).
+ */
+ public CellReference getLastCell() {
+ return _lastCell;
+ }
+ /**
+ * 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, };
+ }
+
+ // 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());
+ 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()]);
+ }
+
+ /**
+ * Example return values:
+ * <table border="0" cellpadding="1" cellspacing="0" summary="Example return values">
+ * <tr><th align='left'>Result</th><th align='left'>Comment</th></tr>
+ * <tr><td>A1:A1</td><td>Single cell area reference without sheet</td></tr>
+ * <tr><td>A1:$C$1</td><td>Multi-cell area reference without sheet</td></tr>
+ * <tr><td>Sheet1!A$1:B4</td><td>Standard sheet name</td></tr>
+ * <tr><td>'O''Brien''s Sales'!B5:C6'&nbsp;</td><td>Sheet name with special characters</td></tr>
+ * </table>
+ * @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());
+ }
+
+ StringBuffer sb = new StringBuffer(32);
+ sb.append(_firstCell.formatAsString());
+ if(!_isSingleCell) {
+ sb.append(CELL_DELIMITER);
+ if(_lastCell.getSheetName() == null) {
+ sb.append(_lastCell.formatAsString());
+ } else {
+ // don't want to include the sheet name twice
+ _lastCell.appendCellReference(sb);
+ }
+ }
+ return sb.toString();
+ }
+
+ public String toString() {
+ StringBuffer sb = new StringBuffer(64);
+ sb.append(getClass().getName()).append(" [");
+ sb.append(formatAsString());
+ sb.append("]");
+ return sb.toString();
+ }
+
+ /**
+ * Separates Area refs in two parts and returns them as separate elements in a String array,
+ * each qualified with the sheet name (if present)
+ *
+ * @return array with one or two elements. never <code>null</code>
+ */
+ private static String[] separateAreaRefs(String reference) {
+ // TODO - refactor cell reference parsing logic to one place.
+ // Current known incarnations:
+ // FormulaParser.GetName()
+ // CellReference.separateRefParts()
+ // AreaReference.separateAreaRefs() (here)
+ // SheetNameFormatter.format() (inverse)
+
+
+ int len = reference.length();
+ int delimiterPos = -1;
+ boolean insideDelimitedName = false;
+ for(int i=0; i<len; i++) {
+ switch(reference.charAt(i)) {
+ case CELL_DELIMITER:
+ if(!insideDelimitedName) {
+ if(delimiterPos >=0) {
+ throw new IllegalArgumentException("More than one cell delimiter '"
+ + CELL_DELIMITER + "' appears in area reference '" + reference + "'");
+ }
+ delimiterPos = i;
+ }
+ default:
+ continue;
+ case SPECIAL_NAME_DELIMITER:
+ // fall through
+ }
+ if(!insideDelimitedName) {
+ insideDelimitedName = true;
+ continue;
+ }
+
+ if(i >= len-1) {
+ // reference ends with the delimited name.
+ // Assume names like: "Sheet1!'A1'" are never legal.
+ throw new IllegalArgumentException("Area reference '" + reference
+ + "' ends with special name delimiter '" + SPECIAL_NAME_DELIMITER + "'");
+ }
+ if(reference.charAt(i+1) == SPECIAL_NAME_DELIMITER) {
+ // two consecutive quotes is the escape sequence for a single one
+ i++; // skip this and keep parsing the special name
+ } else {
+ // this is the end of the delimited name
+ insideDelimitedName = false;
+ }
+ }
+ if(delimiterPos < 0) {
+ return new String[] { reference, };
+ }
+
+ String partA = reference.substring(0, delimiterPos);
+ String partB = reference.substring(delimiterPos+1);
+ if(partB.indexOf(SHEET_NAME_DELIMITER) >=0) {
+ // TODO - are references like "Sheet1!A1:Sheet1:B2" ever valid?
+ // FormulaParser has code to handle that.
+
+ throw new RuntimeException("Unexpected " + SHEET_NAME_DELIMITER
+ + " in second cell reference of '" + reference + "'");
+ }
+
+ int plingPos = partA.lastIndexOf(SHEET_NAME_DELIMITER);
+ if(plingPos < 0) {
+ return new String [] { partA, partB, };
+ }
+
+ String sheetName = partA.substring(0, plingPos + 1); // +1 to include delimiter
+
+ return new String [] { partA, sheetName + partB, };
+ }
+}