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
This commit is contained in:
parent
6c3a086277
commit
2a02163d66
@ -65,6 +65,8 @@
|
||||
<action dev="POI-DEVELOPERS" type="add">Created a common interface for handling Excel files, irrespective of if they are .xls or .xlsx</action>
|
||||
</release>
|
||||
<release version="3.1.1-alpha1" date="2008-??-??">
|
||||
<action dev="POI-DEVELOPERS" type="add">Initial support for embedded movies and controls in HSLF</action>
|
||||
<action dev="POI-DEVELOPERS" type="fix">45358 - signed/unsigned error when parsing 3-d area refs, performance problem evaluating area refs, and ClassCastExcecption in IF()</action>
|
||||
<action dev="POI-DEVELOPERS" type="add">Support for HPBF Publisher hyperlinks, including during text extraction</action>
|
||||
<action dev="POI-DEVELOPERS" type="fix">26321 and 44958 - preserve position of ArrayRecords and TableRecords among cell value records</action>
|
||||
<action dev="POI-DEVELOPERS" type="fix">Impove empty header or footer handling in HWPF HeaderStories</action>
|
||||
|
@ -171,6 +171,27 @@ PL 62 1a 00 00 48 00 00 00 // PL from: 1a62 (6754), len: 48 (72)
|
||||
think that the second 4 bytes of text describes the format
|
||||
of data block at the offset. The format of the text block
|
||||
is easy, but we're still trying to figure out the others.</p>
|
||||
|
||||
<section><title>Structure of TEXT bit</title>
|
||||
<p>This is very simple. All the text for the document is
|
||||
stored in a single bit of the Quill CONTENTS. The text
|
||||
is stored as little endian 16 bit unicode strings.</p>
|
||||
</section>
|
||||
<section><title>Structure of PLC bit</title>
|
||||
<p>The first four bytes seem to hold the count of the
|
||||
entries in the bit, and the second four bytes seem to hold
|
||||
the type. There is then some pre-data, and then data for
|
||||
each of the entries, the exact format dependant on the type.</p>
|
||||
<p>Type 0 has 4 2 byte unsigned ints, then a pair of 2 byte
|
||||
unsigned ints for each entry.</p>
|
||||
<p>Type 4 has 4 2 byte unsigned ints, then a pair of 4 byte
|
||||
unsigned ints for each entry.</p>
|
||||
<p>Type 8 has 7 2 byte unsigned ints, then a pair of 4 byte
|
||||
unsigned ints for each entry.</p>
|
||||
<p>Type 12 holds hyperlinks, and is very much more complex.
|
||||
See <code>org.apache.poi.hpbf.model.qcbits.QCPLCBit</code>
|
||||
for our best guess as to how the contents match up.</p>
|
||||
</section>
|
||||
</section>
|
||||
</body>
|
||||
</document>
|
||||
|
@ -41,7 +41,7 @@
|
||||
lots of offsets to other parts of the file.</p>
|
||||
<p>Our initial aim is to provude a text extractor for the format
|
||||
(now done), and be able to extract hyperlinks from within
|
||||
the document (not yet supported). Additional low level
|
||||
the document (partly supported). Additional low level
|
||||
code to process the file format may follow, if there
|
||||
is demand and developer interest warrant it.</p>
|
||||
<p>At this time, there is no <em>usermodel</em> api or similar.
|
||||
|
@ -62,6 +62,8 @@
|
||||
<action dev="POI-DEVELOPERS" type="add">Created a common interface for handling Excel files, irrespective of if they are .xls or .xlsx</action>
|
||||
</release>
|
||||
<release version="3.1.1-alpha1" date="2008-??-??">
|
||||
<action dev="POI-DEVELOPERS" type="add">Initial support for embedded movies and controls in HSLF</action>
|
||||
<action dev="POI-DEVELOPERS" type="fix">45358 - signed/unsigned error when parsing 3-d area refs, performance problem evaluating area refs, and ClassCastExcecption in IF()</action>
|
||||
<action dev="POI-DEVELOPERS" type="add">Support for HPBF Publisher hyperlinks, including during text extraction</action>
|
||||
<action dev="POI-DEVELOPERS" type="fix">26321 and 44958 - preserve position of ArrayRecords and TableRecords among cell value records</action>
|
||||
<action dev="POI-DEVELOPERS" type="fix">Impove empty header or footer handling in HWPF HeaderStories</action>
|
||||
|
@ -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()) );
|
||||
}
|
||||
|
@ -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();
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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 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;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @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();
|
||||
}
|
@ -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) {
|
||||
|
@ -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() {
|
||||
|
@ -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();
|
||||
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();
|
||||
}
|
||||
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() {
|
||||
|
@ -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");
|
||||
|
@ -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 < amolweb at ya hoo dot com >
|
||||
*
|
||||
*/
|
||||
public final class Area2DEval extends AreaEvalBase {
|
||||
|
||||
public Area2DEval(Ptg ptg, ValueEval[] values) {
|
||||
super((AreaPtg) ptg, values);
|
||||
}
|
||||
}
|
@ -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 < amolweb at ya hoo dot com >
|
||||
*
|
||||
*/
|
||||
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;
|
||||
}
|
||||
}
|
@ -61,13 +61,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
|
||||
@ -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);
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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 < amolweb at ya hoo dot com >
|
||||
*
|
||||
*/
|
||||
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);
|
||||
}
|
||||
}
|
@ -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);
|
||||
}
|
||||
}
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
|
@ -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();
|
||||
}
|
||||
}
|
@ -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);
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
@ -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);
|
||||
}
|
||||
|
@ -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 < amolweb at ya hoo dot com >
|
||||
@ -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();
|
||||
}
|
||||
}
|
||||
|
@ -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)) {
|
||||
|
||||
int rowIx = 0;
|
||||
int columnIx = 0;
|
||||
int areaIx = 0;
|
||||
// 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() + ")");
|
||||
}
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
@ -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();
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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();
|
||||
}
|
||||
|
@ -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 {
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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 < amolweb at ya hoo dot com >
|
||||
*
|
||||
*
|
||||
*/
|
||||
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;
|
||||
|
||||
public DoubleArrayPair(double[] xArray, double[] yArray) {
|
||||
_xArray = xArray;
|
||||
_yArray = yArray;
|
||||
private static abstract class ValueArray implements ValueVector {
|
||||
private final int _size;
|
||||
protected ValueArray(int size) {
|
||||
_size = size;
|
||||
}
|
||||
public double[] getXArray() {
|
||||
return _xArray;
|
||||
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);
|
||||
}
|
||||
public double[] getYArray() {
|
||||
return _yArray;
|
||||
protected abstract ValueEval getItemInternal(int index);
|
||||
public final int getSize() {
|
||||
return _size;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static final class SingleCellValueArray extends ValueArray {
|
||||
private final ValueEval _value;
|
||||
public SingleCellValueArray(ValueEval value) {
|
||||
super(1);
|
||||
_value = value;
|
||||
}
|
||||
protected ValueEval getItemInternal(int index) {
|
||||
return _value;
|
||||
}
|
||||
}
|
||||
|
||||
public final Eval evaluate(Eval[] args, int srcCellRow, short srcCellCol) {
|
||||
if(args.length != 2) {
|
||||
return ErrorEval.VALUE_INVALID;
|
||||
}
|
||||
|
||||
double[][] values;
|
||||
private static final class RefValueArray extends ValueArray {
|
||||
private final RefEval _ref;
|
||||
public RefValueArray(RefEval ref) {
|
||||
super(1);
|
||||
_ref = ref;
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
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);
|
||||
return new NumberEval(result);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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);
|
||||
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;
|
||||
}
|
||||
}
|
||||
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
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < yops.length; i++) {
|
||||
Eval eval = yops[i];
|
||||
if (eval instanceof ErrorEval) {
|
||||
throw new EvaluationException((ErrorEval) eval);
|
||||
}
|
||||
if (firstXerr != null) {
|
||||
throw new EvaluationException(firstXerr);
|
||||
}
|
||||
|
||||
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++;
|
||||
}
|
||||
if (firstYerr != null) {
|
||||
throw new EvaluationException(firstYerr);
|
||||
}
|
||||
|
||||
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 (!accumlatedSome) {
|
||||
throw new EvaluationException(ErrorEval.DIV_ZERO);
|
||||
}
|
||||
if (argY instanceof ErrorEval) {
|
||||
throw new EvaluationException((ErrorEval) argY);
|
||||
return result;
|
||||
}
|
||||
|
||||
private static ValueVector createValueVector(Eval arg) throws EvaluationException {
|
||||
if (arg instanceof ErrorEval) {
|
||||
throw new EvaluationException((ErrorEval) arg);
|
||||
}
|
||||
|
||||
Eval[] xEvals;
|
||||
Eval[] yEvals;
|
||||
if (argX instanceof AreaEval) {
|
||||
AreaEval ae = (AreaEval) argX;
|
||||
xEvals = ae.getValues();
|
||||
} else {
|
||||
xEvals = new Eval[] { argX, };
|
||||
if (arg instanceof AreaEval) {
|
||||
return new AreaValueArray((AreaEval) arg);
|
||||
}
|
||||
|
||||
if (argY instanceof AreaEval) {
|
||||
AreaEval ae = (AreaEval) argY;
|
||||
yEvals = ae.getValues();
|
||||
} else {
|
||||
yEvals = new Eval[] { argY, };
|
||||
if (arg instanceof RefEval) {
|
||||
return new RefValueArray((RefEval) arg);
|
||||
}
|
||||
|
||||
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 (arg instanceof ValueEval) {
|
||||
return new SingleCellValueArray((ValueEval) arg);
|
||||
}
|
||||
throw new RuntimeException("Unexpected eval class (" + arg.getClass().getName() + ")");
|
||||
}
|
||||
}
|
||||
|
@ -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>");
|
||||
|
@ -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)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -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)
|
||||
|
@ -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;
|
||||
super(topLeft, botRight);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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' </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, };
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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 < amolweb at ya hoo dot com >
|
||||
*
|
||||
*
|
||||
*/
|
||||
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);
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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 < amolweb at ya hoo dot com >
|
||||
*/
|
||||
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.
|
||||
|
296
src/java/org/apache/poi/ss/util/AreaReference.java
Normal file
296
src/java/org/apache/poi/ss/util/AreaReference.java
Normal file
@ -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' </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, };
|
||||
}
|
||||
}
|
@ -125,7 +125,7 @@ public class PPTXMLDump {
|
||||
dump(data, pos, size, padding);
|
||||
} else {
|
||||
//dump first 100 bytes of the atom data
|
||||
dump(out, data, pos, size, padding, true);
|
||||
dump(out, data, pos, Math.min(size, data.length-pos), padding, true);
|
||||
}
|
||||
padding--;
|
||||
write(out, "</"+recname + ">" + CR, padding);
|
||||
|
@ -34,7 +34,14 @@ import java.util.Iterator;
|
||||
* @author Yegor Kozlov
|
||||
*/
|
||||
public class Hyperlink {
|
||||
public static final byte LINK_NEXTSLIDE = InteractiveInfoAtom.LINK_NextSlide;
|
||||
public static final byte LINK_PREVIOUSSLIDE = InteractiveInfoAtom.LINK_PreviousSlide;
|
||||
public static final byte LINK_FIRSTSLIDE = InteractiveInfoAtom.LINK_FirstSlide;
|
||||
public static final byte LINK_LASTSLIDE = InteractiveInfoAtom.LINK_LastSlide;
|
||||
public static final byte LINK_URL = InteractiveInfoAtom.LINK_Url;
|
||||
public static final byte LINK_NULL = InteractiveInfoAtom.LINK_NULL;
|
||||
|
||||
private int id=-1;
|
||||
private int type;
|
||||
private String address;
|
||||
private String title;
|
||||
@ -42,7 +49,7 @@ public class Hyperlink {
|
||||
|
||||
/**
|
||||
* Gets the type of the hyperlink action.
|
||||
* Must be a <code>ACTION_*</code> constant defined in <code>InteractiveInfoAtom</code>
|
||||
* Must be a <code>LINK_*</code> constant</code>
|
||||
*
|
||||
* @return the hyperlink URL
|
||||
* @see InteractiveInfoAtom
|
||||
@ -51,6 +58,32 @@ public class Hyperlink {
|
||||
return type;
|
||||
}
|
||||
|
||||
public void setType(int val) {
|
||||
type = val;
|
||||
switch(type){
|
||||
case LINK_NEXTSLIDE:
|
||||
title = "NEXT";
|
||||
address = "1,-1,NEXT";
|
||||
break;
|
||||
case LINK_PREVIOUSSLIDE:
|
||||
title = "PREV";
|
||||
address = "1,-1,PREV";
|
||||
break;
|
||||
case LINK_FIRSTSLIDE:
|
||||
title = "FIRST";
|
||||
address = "1,-1,FIRST";
|
||||
break;
|
||||
case LINK_LASTSLIDE:
|
||||
title = "LAST";
|
||||
address = "1,-1,LAST";
|
||||
break;
|
||||
default:
|
||||
title = "";
|
||||
address = "";
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the hyperlink URL
|
||||
*
|
||||
@ -60,6 +93,18 @@ public class Hyperlink {
|
||||
return address;
|
||||
}
|
||||
|
||||
public void setAddress(String str) {
|
||||
address = str;
|
||||
}
|
||||
|
||||
public int getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(int id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the hyperlink user-friendly title (if different from URL)
|
||||
*
|
||||
@ -69,6 +114,10 @@ public class Hyperlink {
|
||||
return title;
|
||||
}
|
||||
|
||||
public void setTitle(String str) {
|
||||
title = str;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the beginning character position
|
||||
*
|
||||
|
@ -21,6 +21,8 @@ import org.apache.poi.ddf.*;
|
||||
import org.apache.poi.util.LittleEndian;
|
||||
import org.apache.poi.hslf.record.ColorSchemeAtom;
|
||||
import org.apache.poi.hslf.record.Record;
|
||||
import org.apache.poi.hslf.record.InteractiveInfo;
|
||||
import org.apache.poi.hslf.record.InteractiveInfoAtom;
|
||||
import org.apache.poi.hslf.exceptions.HSLFException;
|
||||
|
||||
import java.awt.*;
|
||||
@ -343,4 +345,57 @@ public class SimpleShape extends Shape {
|
||||
_clientData.setRemainingData(out.toByteArray());
|
||||
}
|
||||
}
|
||||
|
||||
public void setHyperlink(Hyperlink link){
|
||||
if(link.getId() == -1){
|
||||
throw new HSLFException("You must call SlideShow.addHyperlink(Hyperlink link) first");
|
||||
}
|
||||
|
||||
EscherClientDataRecord cldata = new EscherClientDataRecord();
|
||||
cldata.setOptions((short)0xF);
|
||||
getSpContainer().getChildRecords().add(cldata);
|
||||
|
||||
InteractiveInfo info = new InteractiveInfo();
|
||||
InteractiveInfoAtom infoAtom = info.getInteractiveInfoAtom();
|
||||
|
||||
switch(link.getType()){
|
||||
case Hyperlink.LINK_FIRSTSLIDE:
|
||||
infoAtom.setAction(InteractiveInfoAtom.ACTION_JUMP);
|
||||
infoAtom.setJump(InteractiveInfoAtom.JUMP_FIRSTSLIDE);
|
||||
infoAtom.setHyperlinkType(InteractiveInfoAtom.LINK_FirstSlide);
|
||||
break;
|
||||
case Hyperlink.LINK_LASTSLIDE:
|
||||
infoAtom.setAction(InteractiveInfoAtom.ACTION_JUMP);
|
||||
infoAtom.setJump(InteractiveInfoAtom.JUMP_LASTSLIDE);
|
||||
infoAtom.setHyperlinkType(InteractiveInfoAtom.LINK_LastSlide);
|
||||
break;
|
||||
case Hyperlink.LINK_NEXTSLIDE:
|
||||
infoAtom.setAction(InteractiveInfoAtom.ACTION_JUMP);
|
||||
infoAtom.setJump(InteractiveInfoAtom.JUMP_NEXTSLIDE);
|
||||
infoAtom.setHyperlinkType(InteractiveInfoAtom.LINK_NextSlide);
|
||||
break;
|
||||
case Hyperlink.LINK_PREVIOUSSLIDE:
|
||||
infoAtom.setAction(InteractiveInfoAtom.ACTION_JUMP);
|
||||
infoAtom.setJump(InteractiveInfoAtom.JUMP_PREVIOUSSLIDE);
|
||||
infoAtom.setHyperlinkType(InteractiveInfoAtom.LINK_PreviousSlide);
|
||||
break;
|
||||
case Hyperlink.LINK_URL:
|
||||
infoAtom.setAction(InteractiveInfoAtom.ACTION_HYPERLINK);
|
||||
infoAtom.setJump(InteractiveInfoAtom.JUMP_NONE);
|
||||
infoAtom.setHyperlinkType(InteractiveInfoAtom.LINK_Url);
|
||||
break;
|
||||
}
|
||||
|
||||
infoAtom.setHyperlinkID(link.getId());
|
||||
|
||||
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||
try {
|
||||
info.writeOut(out);
|
||||
} catch(Exception e){
|
||||
throw new HSLFException(e);
|
||||
}
|
||||
cldata.setRemainingData(out.toByteArray());
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -35,19 +35,19 @@ public class CharFlagsTextProp extends BitMaskTextProp {
|
||||
public static String NAME = "char_flags";
|
||||
public CharFlagsTextProp() {
|
||||
super(2,0xffff, NAME, new String[] {
|
||||
"bold", // 0x0001
|
||||
"italic", // 0x0002
|
||||
"underline", // 0x0004
|
||||
"char_unknown_1",// 0x0008
|
||||
"shadow", // 0x0010
|
||||
"char_unknown_2",// 0x0020
|
||||
"char_unknown_3",// 0x0040
|
||||
"char_unknown_4",// 0x0080
|
||||
"strikethrough", // 0x0100
|
||||
"relief", // 0x0200
|
||||
"reset_numbering", // 0x0400
|
||||
"enable_numbering_1", // 0x0800
|
||||
"enable_numbering_2", // 0x1000
|
||||
"bold", // 0x0001 A bit that specifies whether the characters are bold.
|
||||
"italic", // 0x0002 A bit that specifies whether the characters are italicized.
|
||||
"underline", // 0x0004 A bit that specifies whether the characters are underlined.
|
||||
"char_unknown_1", // 0x0008 Undefined and MUST be ignored.
|
||||
"shadow", // 0x0010 A bit that specifies whether the characters have a shadow effect.
|
||||
"fehint", // 0x0020 A bit that specifies whether characters originated from double-byte input.
|
||||
"char_unknown_2", // 0x0040 Undefined and MUST be ignored.
|
||||
"kumi", // 0x0080 A bit that specifies whether Kumimoji are used for vertical text.
|
||||
"strikethrough", // 0x0100 Undefined and MUST be ignored.
|
||||
"emboss", // 0x0200 A bit that specifies whether the characters are embossed.
|
||||
"char_unknown_3", // 0x0400 Undefined and MUST be ignored.
|
||||
"char_unknown_4", // 0x0800 Undefined and MUST be ignored.
|
||||
"char_unknown_5", // 0x1000 Undefined and MUST be ignored.
|
||||
}
|
||||
);
|
||||
}
|
||||
|
@ -34,6 +34,7 @@ public class TextPropCollection {
|
||||
private int charactersCovered;
|
||||
private short reservedField;
|
||||
private LinkedList textPropList;
|
||||
private int maskSpecial = 0;
|
||||
|
||||
/** Fetch the number of characters this styling applies to */
|
||||
public int getCharactersCovered() { return charactersCovered; }
|
||||
@ -94,21 +95,28 @@ public class TextPropCollection {
|
||||
// If we do, decode that, save it, and shuffle on
|
||||
for(int i=0; i<potentialProperties.length; i++) {
|
||||
// Check there's still data left to read
|
||||
if(dataOffset+bytesPassed >= data.length) {
|
||||
// Out of data, can't be any more properties to go
|
||||
return bytesPassed;
|
||||
}
|
||||
|
||||
|
||||
// Check if this property is found in the mask
|
||||
if((containsField & potentialProperties[i].getMask()) != 0) {
|
||||
if(dataOffset+bytesPassed >= data.length) {
|
||||
// Out of data, can't be any more properties to go
|
||||
// remember the mask and return
|
||||
maskSpecial |= potentialProperties[i].getMask();
|
||||
return bytesPassed;
|
||||
}
|
||||
|
||||
// Bingo, data contains this property
|
||||
TextProp prop = (TextProp)potentialProperties[i].clone();
|
||||
int val = 0;
|
||||
if(prop.getSize() == 2) {
|
||||
val = LittleEndian.getShort(data,dataOffset+bytesPassed);
|
||||
} else {
|
||||
} else if(prop.getSize() == 4){
|
||||
val = LittleEndian.getInt(data,dataOffset+bytesPassed);
|
||||
}
|
||||
} else if (prop.getSize() == 0){
|
||||
//remember "special" bits.
|
||||
maskSpecial |= potentialProperties[i].getMask();
|
||||
continue;
|
||||
}
|
||||
prop.setValue(val);
|
||||
bytesPassed += prop.getSize();
|
||||
textPropList.add(prop);
|
||||
@ -161,15 +169,18 @@ public class TextPropCollection {
|
||||
}
|
||||
|
||||
// Then the mask field
|
||||
int mask = 0;
|
||||
int mask = maskSpecial;
|
||||
for(int i=0; i<textPropList.size(); i++) {
|
||||
TextProp textProp = (TextProp)textPropList.get(i);
|
||||
//sometimes header indicates that the bitmask is present but its value is 0
|
||||
if (textProp instanceof BitMaskTextProp)
|
||||
mask |= (textProp.getWriteMask() == 0 ? 1 : textProp.getWriteMask());
|
||||
else
|
||||
|
||||
if (textProp instanceof BitMaskTextProp) {
|
||||
if(mask == 0) mask |= textProp.getWriteMask();
|
||||
}
|
||||
else {
|
||||
mask |= textProp.getWriteMask();
|
||||
}
|
||||
}
|
||||
}
|
||||
StyleTextPropAtom.writeLittleEndian(mask,o);
|
||||
|
||||
// Then the contents of all the properties
|
||||
@ -178,7 +189,7 @@ public class TextPropCollection {
|
||||
int val = textProp.getValue();
|
||||
if(textProp.getSize() == 2) {
|
||||
StyleTextPropAtom.writeLittleEndian((short)val,o);
|
||||
} else {
|
||||
} else if(textProp.getSize() == 4){
|
||||
StyleTextPropAtom.writeLittleEndian(val,o);
|
||||
}
|
||||
}
|
||||
|
@ -63,14 +63,16 @@ public class ExHyperlink extends RecordContainer {
|
||||
* TODO: Figure out if we should always set both
|
||||
*/
|
||||
public void setLinkURL(String url) {
|
||||
linkDetailsA.setText(url);
|
||||
|
||||
// linkDetailsB isn't present in all PPT versions
|
||||
if(linkDetailsB != null) {
|
||||
linkDetailsB.setText(url);
|
||||
}
|
||||
}
|
||||
|
||||
public void setLinkTitle(String title) {
|
||||
if(linkDetailsA != null) {
|
||||
linkDetailsA.setText(title);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the link details (field A)
|
||||
*/
|
||||
|
@ -124,47 +124,54 @@ public class StyleTextPropAtom extends RecordAtom
|
||||
|
||||
/** All the different kinds of paragraph properties we might handle */
|
||||
public static TextProp[] paragraphTextPropTypes = new TextProp[] {
|
||||
new ParagraphFlagsTextProp(),
|
||||
new TextProp(0, 0x1, "hasBullet"),
|
||||
new TextProp(0, 0x2, "hasBulletFont"),
|
||||
new TextProp(0, 0x4, "hasBulletColor"),
|
||||
new TextProp(0, 0x8, "hasBulletSize"),
|
||||
new ParagraphFlagsTextProp(),
|
||||
new TextProp(2, 0x80, "bullet.char"),
|
||||
new TextProp(2, 0x10, "bullet.font"),
|
||||
new TextProp(2, 0x40, "bullet.size"),
|
||||
new TextProp(4, 0x20, "bullet.color"),
|
||||
new AlignmentTextProp(),
|
||||
new TextProp(2, 0x100, "text.offset"),
|
||||
new TextProp(2, 0x200, "para_unknown_2"),
|
||||
new TextProp(2, 0x400, "bullet.offset"),
|
||||
new TextProp(2, 0x1000, "linespacing"),
|
||||
new TextProp(2, 0x2000, "spacebefore"),
|
||||
new TextProp(2, 0x4000, "spaceafter"),
|
||||
new TextProp(2, 0x8000, "para_unknown_4"),
|
||||
new TextProp(2, 0x10000, "para_unknown_5"),
|
||||
new TextProp(2, 0xA0000, "para_unknown_6"),
|
||||
new TextProp(2, 0x200000, "para_unknown_7")
|
||||
new TextProp(2, 0x1000, "linespacing"),
|
||||
new TextProp(2, 0x2000, "spacebefore"),
|
||||
new TextProp(2, 0x4000, "spaceafter"),
|
||||
new TextProp(2, 0x8000, "defaultTabSize"),
|
||||
new TextProp(2, 0x100000, "tabStops"),
|
||||
new TextProp(2, 0x10000, "fontAlign"),
|
||||
new TextProp(2, 0xA0000, "wrapFlags"),
|
||||
new TextProp(2, 0x200000, "textDirection")
|
||||
};
|
||||
/** All the different kinds of character properties we might handle */
|
||||
public static TextProp[] characterTextPropTypes = new TextProp[] {
|
||||
new CharFlagsTextProp(),
|
||||
new TextProp(0, 0x1, "bold"),
|
||||
new TextProp(0, 0x2, "italic"),
|
||||
new TextProp(0, 0x4, "underline"),
|
||||
new TextProp(0, 0x8, "unused1"),
|
||||
new TextProp(0, 0x10, "shadow"),
|
||||
new TextProp(0, 0x20, "fehint"),
|
||||
new TextProp(0, 0x40, "unused2"),
|
||||
new TextProp(0, 0x80, "kumi"),
|
||||
new TextProp(0, 0x100, "unused3"),
|
||||
new TextProp(0, 0x200, "emboss"),
|
||||
new CharFlagsTextProp(),
|
||||
new TextProp(2, 0x10000, "font.index"),
|
||||
new TextProp(2, 0x200000, "asian_or_complex"),
|
||||
new TextProp(2, 0x400000, "char_unknown_2"),
|
||||
new TextProp(2, 0x800000, "symbol"),
|
||||
new TextProp(0, 0x100000, "pp10ext"),
|
||||
new TextProp(2, 0x200000, "asian.font.index"),
|
||||
new TextProp(2, 0x400000, "ansi.font.index"),
|
||||
new TextProp(2, 0x800000, "symbol.font.index"),
|
||||
new TextProp(2, 0x20000, "font.size"),
|
||||
new TextProp(4, 0x40000, "font.color"),
|
||||
new TextProp(2, 0x80000, "superscript"),
|
||||
new TextProp(2, 0x100000, "char_unknown_1"),
|
||||
new TextProp(2, 0x1000000, "char_unknown_3"),
|
||||
new TextProp(2, 0x2000000, "char_unknown_4"),
|
||||
new TextProp(2, 0x4000000, "char_unknown_5"),
|
||||
new TextProp(2, 0x8000000, "char_unknown_6"),
|
||||
new TextProp(2, 0x10000000, "char_unknown_7"),
|
||||
new TextProp(2, 0x20000000, "char_unknown_8"),
|
||||
new TextProp(2, 0x40000000, "char_unknown_9"),
|
||||
new TextProp(2, 0x80000000, "char_unknown_10"),
|
||||
};
|
||||
new TextProp(2, 0x80000, "superscript"),
|
||||
|
||||
};
|
||||
|
||||
/* *************** record code follows ********************** */
|
||||
|
||||
/**
|
||||
/**
|
||||
* For the Text Style Properties (StyleTextProp) Atom
|
||||
*/
|
||||
public StyleTextPropAtom(byte[] source, int start, int len) {
|
||||
@ -192,7 +199,7 @@ public class StyleTextPropAtom extends RecordAtom
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
/**
|
||||
* A new set of text style properties for some text without any.
|
||||
*/
|
||||
public StyleTextPropAtom(int parentTextSize) {
|
||||
@ -209,11 +216,11 @@ public class StyleTextPropAtom extends RecordAtom
|
||||
paragraphStyles = new LinkedList();
|
||||
charStyles = new LinkedList();
|
||||
|
||||
TextPropCollection defaultParagraphTextProps =
|
||||
TextPropCollection defaultParagraphTextProps =
|
||||
new TextPropCollection(parentTextSize, (short)0);
|
||||
paragraphStyles.add(defaultParagraphTextProps);
|
||||
|
||||
TextPropCollection defaultCharacterTextProps =
|
||||
TextPropCollection defaultCharacterTextProps =
|
||||
new TextPropCollection(parentTextSize);
|
||||
charStyles.add(defaultCharacterTextProps);
|
||||
|
||||
@ -269,8 +276,7 @@ public class StyleTextPropAtom extends RecordAtom
|
||||
textHandled += textLen;
|
||||
pos += 4;
|
||||
|
||||
// Fetch the 2 byte value that is safe to ignore as 0
|
||||
short paraIgn = LittleEndian.getShort(rawContents,pos);
|
||||
short indent = LittleEndian.getShort(rawContents,pos);
|
||||
pos += 2;
|
||||
|
||||
// Grab the 4 byte value that tells us what properties follow
|
||||
@ -278,7 +284,7 @@ public class StyleTextPropAtom extends RecordAtom
|
||||
pos += 4;
|
||||
|
||||
// Now make sense of those properties
|
||||
TextPropCollection thisCollection = new TextPropCollection(textLen, paraIgn);
|
||||
TextPropCollection thisCollection = new TextPropCollection(textLen, indent);
|
||||
int plSize = thisCollection.buildTextPropList(
|
||||
paraFlags, paragraphTextPropTypes, rawContents, pos);
|
||||
pos += plSize;
|
||||
|
@ -920,7 +920,7 @@ public final class SlideShow {
|
||||
* @return 0-based index of the control
|
||||
*/
|
||||
public int addControl(String name, String progId) {
|
||||
ExObjList lst = _documentRecord.getExObjList();
|
||||
ExObjList lst = (ExObjList)_documentRecord.findFirstOfType(RecordTypes.ExObjList.typeID);
|
||||
if (lst == null) {
|
||||
lst = new ExObjList();
|
||||
_documentRecord.addChildAfter(lst, _documentRecord.getDocumentAtom());
|
||||
@ -943,4 +943,31 @@ public final class SlideShow {
|
||||
|
||||
return objectId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a hyperlink to this presentation
|
||||
*
|
||||
* @return 0-based index of the hyperlink
|
||||
*/
|
||||
public int addHyperlink(Hyperlink link) {
|
||||
ExObjList lst = (ExObjList)_documentRecord.findFirstOfType(RecordTypes.ExObjList.typeID);
|
||||
if (lst == null) {
|
||||
lst = new ExObjList();
|
||||
_documentRecord.addChildAfter(lst, _documentRecord.getDocumentAtom());
|
||||
}
|
||||
ExObjListAtom objAtom = lst.getExObjListAtom();
|
||||
//increment the object ID seed
|
||||
int objectId = (int) objAtom.getObjectIDSeed() + 1;
|
||||
objAtom.setObjectIDSeed(objectId);
|
||||
|
||||
ExHyperlink ctrl = new ExHyperlink();
|
||||
ExHyperlinkAtom obj = ctrl.getExHyperlinkAtom();
|
||||
obj.setNumber(objectId);
|
||||
ctrl.setLinkURL(link.getAddress());
|
||||
ctrl.setLinkTitle(link.getTitle());
|
||||
lst.addChildAfter(ctrl, objAtom);
|
||||
link.setId(objectId);
|
||||
|
||||
return objectId;
|
||||
}
|
||||
}
|
||||
|
@ -760,12 +760,8 @@ public final class HSSFChart {
|
||||
r.setIndexNumberFmtRecord( (short) 0 );
|
||||
LinkedDataFormulaField formula = new LinkedDataFormulaField();
|
||||
Stack tokens = new Stack();
|
||||
Area3DPtg p = new Area3DPtg();
|
||||
p.setExternSheetIndex( (short) 0 );
|
||||
p.setFirstColumn( (short) 1 );
|
||||
p.setLastColumn( (short) 1 );
|
||||
p.setFirstRow( (short) 0 );
|
||||
p.setLastRow( (short) 31 );
|
||||
Area3DPtg p = new Area3DPtg(0, 31, 1, 1,
|
||||
false, false, false, false, 0);
|
||||
tokens.add( p );
|
||||
formula.setFormulaTokens( tokens );
|
||||
r.setFormulaOfLink( formula );
|
||||
@ -781,12 +777,8 @@ public final class HSSFChart {
|
||||
r.setIndexNumberFmtRecord( (short) 0 );
|
||||
LinkedDataFormulaField formula = new LinkedDataFormulaField();
|
||||
Stack tokens = new Stack();
|
||||
Area3DPtg p = new Area3DPtg();
|
||||
p.setExternSheetIndex( (short) 0 );
|
||||
p.setFirstColumn( (short) 0 );
|
||||
p.setLastColumn( (short) 0 );
|
||||
p.setFirstRow( (short) 0 );
|
||||
p.setLastRow( (short) 31 );
|
||||
Area3DPtg p = new Area3DPtg(0, 31, 0, 0,
|
||||
false, false, false, false, 0);
|
||||
tokens.add( p );
|
||||
formula.setFormulaTokens( tokens );
|
||||
r.setFormulaOfLink( formula );
|
||||
|
File diff suppressed because it is too large
Load Diff
Binary file not shown.
@ -24,6 +24,7 @@ import org.apache.poi.hssf.HSSFTestDataSamples;
|
||||
import org.apache.poi.hssf.model.FormulaParser.FormulaParseException;
|
||||
import org.apache.poi.hssf.record.formula.AbstractFunctionPtg;
|
||||
import org.apache.poi.hssf.record.formula.AddPtg;
|
||||
import org.apache.poi.hssf.record.formula.AreaI;
|
||||
import org.apache.poi.hssf.record.formula.AreaPtg;
|
||||
import org.apache.poi.hssf.record.formula.AttrPtg;
|
||||
import org.apache.poi.hssf.record.formula.BoolPtg;
|
||||
@ -836,4 +837,29 @@ public final class TestFormulaParser extends TestCase {
|
||||
}
|
||||
cell.setCellFormula("count(fp1)"); // plain cell ref, col is in range
|
||||
}
|
||||
}
|
||||
|
||||
public void testParseAreaRefHighRow_bug45358() {
|
||||
Ptg[] ptgs;
|
||||
AreaI aptg;
|
||||
|
||||
HSSFWorkbook book = new HSSFWorkbook();
|
||||
book.createSheet("Sheet1");
|
||||
|
||||
ptgs = FormulaParser.parse("Sheet1!A10:A40000", book);
|
||||
aptg = (AreaI) ptgs[0];
|
||||
if (aptg.getLastRow() == -25537) {
|
||||
throw new AssertionFailedError("Identified bug 45358");
|
||||
}
|
||||
assertEquals(39999, aptg.getLastRow());
|
||||
|
||||
ptgs = FormulaParser.parse("Sheet1!A10:A65536", book);
|
||||
aptg = (AreaI) ptgs[0];
|
||||
assertEquals(65535, aptg.getLastRow());
|
||||
|
||||
// plain area refs should be ok too
|
||||
ptgs = parseFormula("A10:A65536");
|
||||
aptg = (AreaI) ptgs[0];
|
||||
assertEquals(65535, aptg.getLastRow());
|
||||
|
||||
}
|
||||
}
|
@ -1,4 +1,3 @@
|
||||
|
||||
/* ====================================================================
|
||||
Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
contributor license agreements. See the NOTICE file distributed with
|
||||
@ -15,8 +14,6 @@
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
==================================================================== */
|
||||
|
||||
|
||||
|
||||
package org.apache.poi.hssf.record;
|
||||
|
||||
@ -33,9 +30,7 @@ import java.util.Stack;
|
||||
*
|
||||
* @author Glen Stampoultzis (glens at apache.org)
|
||||
*/
|
||||
public class TestLinkedDataRecord
|
||||
extends TestCase
|
||||
{
|
||||
public final class TestLinkedDataRecord extends TestCase {
|
||||
|
||||
/*
|
||||
The records below are records that would appear in a simple bar chart
|
||||
@ -160,14 +155,7 @@ recordid = 0x1051, size =8
|
||||
(byte)0x00,(byte)0x00, // index to last column and relative flags
|
||||
};
|
||||
|
||||
public TestLinkedDataRecord(String name)
|
||||
{
|
||||
super(name);
|
||||
}
|
||||
|
||||
public void testLoad()
|
||||
throws Exception
|
||||
{
|
||||
public void testLoad() {
|
||||
|
||||
LinkedDataRecord record = new LinkedDataRecord(new TestcaseRecordInputStream((short)0x1051, (short)data.length, data));
|
||||
assertEquals( LinkedDataRecord.LINK_TYPE_VALUES, record.getLinkType());
|
||||
@ -176,19 +164,11 @@ recordid = 0x1051, size =8
|
||||
assertEquals( false, record.isCustomNumberFormat() );
|
||||
assertEquals( 0, record.getIndexNumberFmtRecord());
|
||||
|
||||
Area3DPtg ptg = new Area3DPtg();
|
||||
ptg.setExternSheetIndex((short)0);
|
||||
ptg.setFirstColumn((short)0);
|
||||
ptg.setLastColumn((short)0);
|
||||
ptg.setFirstRow((short)0);
|
||||
ptg.setLastRow((short)7936);
|
||||
ptg.setFirstColRelative(false);
|
||||
ptg.setLastColRelative(false);
|
||||
ptg.setFirstRowRelative(false);
|
||||
ptg.setLastRowRelative(false);
|
||||
Stack s = new Stack();
|
||||
s.push(ptg);
|
||||
assertEquals( s, record.getFormulaOfLink().getFormulaTokens() );
|
||||
Area3DPtg ptgExpected = new Area3DPtg(0, 7936, 0, 0,
|
||||
false, false, false, false, 0);
|
||||
|
||||
Object ptgActual = record.getFormulaOfLink().getFormulaTokens().get(0);
|
||||
assertEquals(ptgExpected.toString(), ptgActual.toString());
|
||||
|
||||
assertEquals( data.length + 4, record.getRecordSize() );
|
||||
|
||||
@ -196,24 +176,15 @@ recordid = 0x1051, size =8
|
||||
|
||||
}
|
||||
|
||||
public void testStore()
|
||||
{
|
||||
public void testStore() {
|
||||
LinkedDataRecord record = new LinkedDataRecord();
|
||||
record.setLinkType( LinkedDataRecord.LINK_TYPE_VALUES );
|
||||
record.setReferenceType( LinkedDataRecord.REFERENCE_TYPE_WORKSHEET );
|
||||
record.setOptions( (short)0 );
|
||||
record.setCustomNumberFormat( false );
|
||||
record.setIndexNumberFmtRecord( (short)0 );
|
||||
Area3DPtg ptg = new Area3DPtg();
|
||||
ptg.setExternSheetIndex((short)0);
|
||||
ptg.setFirstColumn((short)0);
|
||||
ptg.setLastColumn((short)0);
|
||||
ptg.setFirstRow((short)0);
|
||||
ptg.setLastRow((short)7936);
|
||||
ptg.setFirstColRelative(false);
|
||||
ptg.setLastColRelative(false);
|
||||
ptg.setFirstRowRelative(false);
|
||||
ptg.setLastRowRelative(false);
|
||||
Area3DPtg ptg = new Area3DPtg(0, 7936, 0, 0,
|
||||
false, false, false, false, 0);
|
||||
Stack s = new Stack();
|
||||
s.push(ptg);
|
||||
LinkedDataFormulaField formulaOfLink = new LinkedDataFormulaField();
|
||||
|
@ -20,7 +20,8 @@ package org.apache.poi.hssf.record.formula.eval;
|
||||
import junit.framework.AssertionFailedError;
|
||||
import junit.framework.TestCase;
|
||||
|
||||
import org.apache.poi.hssf.record.formula.Area3DPtg;
|
||||
import org.apache.poi.hssf.record.formula.AreaPtg;
|
||||
import org.apache.poi.hssf.record.formula.functions.EvalFactory;
|
||||
|
||||
/**
|
||||
* Tests for <tt>AreaEval</tt>
|
||||
@ -30,8 +31,8 @@ import org.apache.poi.hssf.record.formula.Area3DPtg;
|
||||
public final class TestAreaEval extends TestCase {
|
||||
|
||||
public void testGetValue_bug44950() {
|
||||
|
||||
Area3DPtg ptg = new Area3DPtg("B2:D3", (short)0);
|
||||
// TODO - this test probably isn't testing much anymore
|
||||
AreaPtg ptg = new AreaPtg("B2:D3");
|
||||
NumberEval one = new NumberEval(1);
|
||||
ValueEval[] values = {
|
||||
one,
|
||||
@ -41,7 +42,7 @@ public final class TestAreaEval extends TestCase {
|
||||
new NumberEval(5),
|
||||
new NumberEval(6),
|
||||
};
|
||||
AreaEval ae = new Area3DEval(ptg, values);
|
||||
AreaEval ae = EvalFactory.createAreaEval(ptg, values);
|
||||
if (one == ae.getValueAt(1, 2)) {
|
||||
throw new AssertionFailedError("Identified bug 44950 a");
|
||||
}
|
||||
|
@ -18,22 +18,23 @@
|
||||
|
||||
package org.apache.poi.hssf.record.formula.eval;
|
||||
|
||||
import junit.framework.TestCase;
|
||||
|
||||
import org.apache.poi.hssf.record.formula.AreaPtg;
|
||||
import org.apache.poi.hssf.record.formula.UnaryPlusPtg;
|
||||
import org.apache.poi.hssf.record.formula.functions.EvalFactory;
|
||||
import org.apache.poi.hssf.record.formula.functions.NumericFunctionInvoker;
|
||||
|
||||
import junit.framework.TestCase;
|
||||
|
||||
/**
|
||||
* Test for unary plus operator evaluator.
|
||||
*
|
||||
*
|
||||
* @author Josh Micich
|
||||
*/
|
||||
public final class TestUnaryPlusEval extends TestCase {
|
||||
|
||||
|
||||
/**
|
||||
* Test for bug observable at svn revision 618865 (5-Feb-2008)<br/>
|
||||
* The code for handling column operands had been copy-pasted from the row handling code.
|
||||
* The code for handling column operands had been copy-pasted from the row handling code.
|
||||
*/
|
||||
public void testColumnOperand() {
|
||||
|
||||
@ -42,15 +43,14 @@ public final class TestUnaryPlusEval extends TestCase {
|
||||
short colNum = (short)5;
|
||||
AreaPtg areaPtg = new AreaPtg(firstRow, lastRow, colNum, colNum, false, false, false, false);
|
||||
ValueEval[] values = {
|
||||
new NumberEval(27),
|
||||
new NumberEval(29),
|
||||
new NumberEval(35), // value in row 10
|
||||
new NumberEval(37),
|
||||
new NumberEval(38),
|
||||
new NumberEval(27),
|
||||
new NumberEval(29),
|
||||
new NumberEval(35), // value in row 10
|
||||
new NumberEval(37),
|
||||
new NumberEval(38),
|
||||
};
|
||||
Eval areaEval = new Area2DEval(areaPtg, values);
|
||||
Eval[] args = {
|
||||
areaEval,
|
||||
Eval[] args = {
|
||||
EvalFactory.createAreaEval(areaPtg, values),
|
||||
};
|
||||
|
||||
double result = NumericFunctionInvoker.invoke(new UnaryPlusEval(UnaryPlusPtg.instance), args, 10, (short)20);
|
||||
|
@ -14,17 +14,17 @@
|
||||
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.AreaPtg;
|
||||
import org.apache.poi.hssf.record.formula.Ref3DPtg;
|
||||
import org.apache.poi.hssf.record.formula.RefPtg;
|
||||
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.AreaEvalBase;
|
||||
import org.apache.poi.hssf.record.formula.eval.NumberEval;
|
||||
import org.apache.poi.hssf.record.formula.eval.Ref2DEval;
|
||||
import org.apache.poi.hssf.record.formula.eval.RefEval;
|
||||
import org.apache.poi.hssf.record.formula.eval.RefEvalBase;
|
||||
import org.apache.poi.hssf.record.formula.eval.ValueEval;
|
||||
|
||||
/**
|
||||
@ -32,7 +32,7 @@ import org.apache.poi.hssf.record.formula.eval.ValueEval;
|
||||
*
|
||||
* @author Josh Micich
|
||||
*/
|
||||
final class EvalFactory {
|
||||
public final class EvalFactory {
|
||||
|
||||
private EvalFactory() {
|
||||
// no instances of this class
|
||||
@ -44,6 +44,14 @@ final class EvalFactory {
|
||||
*/
|
||||
public static AreaEval createAreaEval(String areaRefStr, ValueEval[] values) {
|
||||
AreaPtg areaPtg = new AreaPtg(areaRefStr);
|
||||
return createAreaEval(areaPtg, values);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a dummy AreaEval
|
||||
* @param values empty (<code>null</code>) entries in this array will be converted to NumberEval.ZERO
|
||||
*/
|
||||
public static AreaEval createAreaEval(AreaPtg areaPtg, ValueEval[] values) {
|
||||
int nCols = areaPtg.getLastColumn() - areaPtg.getFirstColumn() + 1;
|
||||
int nRows = areaPtg.getLastRow() - areaPtg.getFirstRow() + 1;
|
||||
int nExpected = nRows * nCols;
|
||||
@ -55,13 +63,57 @@ final class EvalFactory {
|
||||
values[i] = NumberEval.ZERO;
|
||||
}
|
||||
}
|
||||
return new Area2DEval(areaPtg, values);
|
||||
return new MockAreaEval(areaPtg, values);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a single RefEval (with value zero)
|
||||
*/
|
||||
public static RefEval createRefEval(String refStr) {
|
||||
return new Ref2DEval(new RefPtg(refStr), NumberEval.ZERO);
|
||||
return createRefEval(refStr, NumberEval.ZERO);
|
||||
}
|
||||
public static RefEval createRefEval(String refStr, ValueEval value) {
|
||||
return new MockRefEval(new RefPtg(refStr), value);
|
||||
}
|
||||
|
||||
private static final class MockAreaEval extends AreaEvalBase {
|
||||
private final ValueEval[] _values;
|
||||
public MockAreaEval(AreaPtg areaPtg, ValueEval[] values) {
|
||||
super(areaPtg);
|
||||
_values = values;
|
||||
}
|
||||
public ValueEval getRelativeValue(int relativeRowIndex, int relativeColumnIndex) {
|
||||
if (relativeRowIndex < 0 || relativeRowIndex >=getHeight()) {
|
||||
throw new IllegalArgumentException("row index out of range");
|
||||
}
|
||||
int width = getWidth();
|
||||
if (relativeColumnIndex < 0 || relativeColumnIndex >=width) {
|
||||
throw new IllegalArgumentException("column index out of range");
|
||||
}
|
||||
int oneDimensionalIndex = relativeRowIndex * width + relativeColumnIndex;
|
||||
return _values[oneDimensionalIndex];
|
||||
}
|
||||
public AreaEval offset(int relFirstRowIx, int relLastRowIx, int relFirstColIx, int relLastColIx) {
|
||||
throw new RuntimeException("Operation not implemented on this mock object");
|
||||
}
|
||||
}
|
||||
|
||||
private static final class MockRefEval extends RefEvalBase {
|
||||
private final ValueEval _value;
|
||||
public MockRefEval(RefPtg ptg, ValueEval value) {
|
||||
super(ptg.getRow(), ptg.getColumn());
|
||||
_value = value;
|
||||
}
|
||||
public MockRefEval(Ref3DPtg ptg, ValueEval value) {
|
||||
super(ptg.getRow(), ptg.getColumn());
|
||||
_value = value;
|
||||
}
|
||||
public ValueEval getInnerValueEval() {
|
||||
return _value;
|
||||
}
|
||||
public AreaEval offset(int relFirstRowIx, int relLastRowIx, int relFirstColIx, int relLastColIx) {
|
||||
throw new RuntimeException("Operation not implemented on this mock object");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -21,9 +21,7 @@ import junit.framework.AssertionFailedError;
|
||||
import junit.framework.TestCase;
|
||||
|
||||
import org.apache.poi.hssf.HSSFTestDataSamples;
|
||||
import org.apache.poi.hssf.record.formula.AreaPtg;
|
||||
import org.apache.poi.hssf.record.formula.RefPtg;
|
||||
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;
|
||||
@ -91,7 +89,7 @@ public final class TestCountFuncs extends TestCase {
|
||||
BoolEval.TRUE,
|
||||
BlankEval.INSTANCE,
|
||||
};
|
||||
range = createAreaEval("A1:B3", values);
|
||||
range = EvalFactory.createAreaEval("A1:B3", values);
|
||||
confirmCountIf(2, range, BoolEval.TRUE);
|
||||
|
||||
// when criteria is numeric
|
||||
@ -103,7 +101,7 @@ public final class TestCountFuncs extends TestCase {
|
||||
new NumberEval(2),
|
||||
BoolEval.TRUE,
|
||||
};
|
||||
range = createAreaEval("A1:B3", values);
|
||||
range = EvalFactory.createAreaEval("A1:B3", values);
|
||||
confirmCountIf(3, range, new NumberEval(2));
|
||||
// note - same results when criteria is a string that parses as the number with the same value
|
||||
confirmCountIf(3, range, new StringEval("2.00"));
|
||||
@ -126,20 +124,15 @@ public final class TestCountFuncs extends TestCase {
|
||||
new NumberEval(25),
|
||||
new NumberEval(25),
|
||||
};
|
||||
Area2DEval arg0 = new Area2DEval(new AreaPtg("C1:C6"), values);
|
||||
AreaEval arg0 = EvalFactory.createAreaEval("C1:C6", values);
|
||||
|
||||
Ref2DEval criteriaArg = new Ref2DEval(new RefPtg("A1"), new NumberEval(25));
|
||||
ValueEval criteriaArg = EvalFactory.createRefEval("A1", new NumberEval(25));
|
||||
Eval[] args= { arg0, criteriaArg, };
|
||||
|
||||
double actual = NumericFunctionInvoker.invoke(new Countif(), args);
|
||||
assertEquals(4, actual, 0D);
|
||||
}
|
||||
|
||||
|
||||
private static AreaEval createAreaEval(String areaRefStr, ValueEval[] values) {
|
||||
return new Area2DEval(new AreaPtg(areaRefStr), values);
|
||||
}
|
||||
|
||||
private static void confirmCountA(int expected, Eval[] args) {
|
||||
double result = NumericFunctionInvoker.invoke(new Counta(), args);
|
||||
assertEquals(expected, result, 0);
|
||||
|
@ -19,8 +19,7 @@ package org.apache.poi.hssf.record.formula.functions;
|
||||
|
||||
import junit.framework.TestCase;
|
||||
|
||||
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.Eval;
|
||||
import org.apache.poi.hssf.record.formula.eval.NumberEval;
|
||||
import org.apache.poi.hssf.record.formula.eval.ValueEval;
|
||||
@ -68,7 +67,7 @@ public final class TestIndex extends TestCase {
|
||||
for (int i = 0; i < values.length; i++) {
|
||||
values[i] = new NumberEval(dValues[i]);
|
||||
}
|
||||
Area2DEval arg0 = new Area2DEval(new AreaPtg(areaRefString), values);
|
||||
AreaEval arg0 = EvalFactory.createAreaEval(areaRefString, values);
|
||||
|
||||
Eval[] args;
|
||||
if (colNum > 0) {
|
||||
|
@ -19,8 +19,6 @@ package org.apache.poi.hssf.record.formula.functions;
|
||||
|
||||
import junit.framework.TestCase;
|
||||
|
||||
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.BoolEval;
|
||||
import org.apache.poi.hssf.record.formula.eval.ErrorEval;
|
||||
@ -32,7 +30,7 @@ import org.apache.poi.hssf.record.formula.eval.ValueEval;
|
||||
|
||||
/**
|
||||
* Test cases for MATCH()
|
||||
*
|
||||
*
|
||||
* @author Josh Micich
|
||||
*/
|
||||
public final class TestMatch extends TestCase {
|
||||
@ -41,8 +39,8 @@ public final class TestMatch extends TestCase {
|
||||
private static final NumberEval MATCH_EXACT = new NumberEval(0);
|
||||
/** greater than or equal to */
|
||||
private static final NumberEval MATCH_SMALLEST_GTE = new NumberEval(-1);
|
||||
|
||||
|
||||
|
||||
|
||||
private static Eval invokeMatch(Eval lookup_value, Eval lookup_array, Eval match_type) {
|
||||
Eval[] args = { lookup_value, lookup_array, match_type, };
|
||||
return new Match().evaluate(args, -1, (short)-1);
|
||||
@ -54,26 +52,19 @@ public final class TestMatch extends TestCase {
|
||||
NumericValueEval nve = (NumericValueEval)actualEval;
|
||||
assertEquals(expected, nve.getNumberValue(), 0);
|
||||
}
|
||||
/**
|
||||
* Convenience method
|
||||
* @return <code>new Area2DEval(new AreaPtg(ref), values)</code>
|
||||
*/
|
||||
private static AreaEval createAreaEval(String ref, ValueEval[] values) {
|
||||
return new Area2DEval(new AreaPtg(ref), values);
|
||||
}
|
||||
|
||||
|
||||
public void testSimpleNumber() {
|
||||
|
||||
|
||||
ValueEval[] values = {
|
||||
new NumberEval(4),
|
||||
new NumberEval(5),
|
||||
new NumberEval(10),
|
||||
new NumberEval(10),
|
||||
new NumberEval(25),
|
||||
new NumberEval(4),
|
||||
new NumberEval(5),
|
||||
new NumberEval(10),
|
||||
new NumberEval(10),
|
||||
new NumberEval(25),
|
||||
};
|
||||
|
||||
AreaEval ae = createAreaEval("A1:A5", values);
|
||||
|
||||
|
||||
AreaEval ae = EvalFactory.createAreaEval("A1:A5", values);
|
||||
|
||||
confirmInt(2, invokeMatch(new NumberEval(5), ae, MATCH_LARGEST_LTE));
|
||||
confirmInt(2, invokeMatch(new NumberEval(5), ae, MATCH_EXACT));
|
||||
confirmInt(4, invokeMatch(new NumberEval(10), ae, MATCH_LARGEST_LTE));
|
||||
@ -81,19 +72,19 @@ public final class TestMatch extends TestCase {
|
||||
confirmInt(4, invokeMatch(new NumberEval(20), ae, MATCH_LARGEST_LTE));
|
||||
assertEquals(ErrorEval.NA, invokeMatch(new NumberEval(20), ae, MATCH_EXACT));
|
||||
}
|
||||
|
||||
|
||||
public void testReversedNumber() {
|
||||
|
||||
|
||||
ValueEval[] values = {
|
||||
new NumberEval(25),
|
||||
new NumberEval(10),
|
||||
new NumberEval(10),
|
||||
new NumberEval(10),
|
||||
new NumberEval(4),
|
||||
new NumberEval(25),
|
||||
new NumberEval(10),
|
||||
new NumberEval(10),
|
||||
new NumberEval(10),
|
||||
new NumberEval(4),
|
||||
};
|
||||
|
||||
AreaEval ae = createAreaEval("A1:A5", values);
|
||||
|
||||
|
||||
AreaEval ae = EvalFactory.createAreaEval("A1:A5", values);
|
||||
|
||||
confirmInt(2, invokeMatch(new NumberEval(10), ae, MATCH_SMALLEST_GTE));
|
||||
confirmInt(2, invokeMatch(new NumberEval(10), ae, MATCH_EXACT));
|
||||
confirmInt(4, invokeMatch(new NumberEval(9), ae, MATCH_SMALLEST_GTE));
|
||||
@ -101,19 +92,19 @@ public final class TestMatch extends TestCase {
|
||||
assertEquals(ErrorEval.NA, invokeMatch(new NumberEval(20), ae, MATCH_EXACT));
|
||||
assertEquals(ErrorEval.NA, invokeMatch(new NumberEval(26), ae, MATCH_SMALLEST_GTE));
|
||||
}
|
||||
|
||||
|
||||
public void testSimpleString() {
|
||||
|
||||
|
||||
ValueEval[] values = {
|
||||
new StringEval("Albert"),
|
||||
new StringEval("Charles"),
|
||||
new StringEval("Ed"),
|
||||
new StringEval("Greg"),
|
||||
new StringEval("Ian"),
|
||||
new StringEval("Albert"),
|
||||
new StringEval("Charles"),
|
||||
new StringEval("Ed"),
|
||||
new StringEval("Greg"),
|
||||
new StringEval("Ian"),
|
||||
};
|
||||
|
||||
AreaEval ae = createAreaEval("A1:A5", values);
|
||||
|
||||
|
||||
AreaEval ae = EvalFactory.createAreaEval("A1:A5", values);
|
||||
|
||||
// Note String comparisons are case insensitive
|
||||
confirmInt(3, invokeMatch(new StringEval("Ed"), ae, MATCH_LARGEST_LTE));
|
||||
confirmInt(3, invokeMatch(new StringEval("eD"), ae, MATCH_LARGEST_LTE));
|
||||
@ -122,90 +113,90 @@ public final class TestMatch extends TestCase {
|
||||
confirmInt(4, invokeMatch(new StringEval("Hugh"), ae, MATCH_LARGEST_LTE));
|
||||
assertEquals(ErrorEval.NA, invokeMatch(new StringEval("Hugh"), ae, MATCH_EXACT));
|
||||
}
|
||||
|
||||
|
||||
public void testSimpleBoolean() {
|
||||
|
||||
|
||||
ValueEval[] values = {
|
||||
BoolEval.FALSE,
|
||||
BoolEval.FALSE,
|
||||
BoolEval.TRUE,
|
||||
BoolEval.TRUE,
|
||||
BoolEval.FALSE,
|
||||
BoolEval.FALSE,
|
||||
BoolEval.TRUE,
|
||||
BoolEval.TRUE,
|
||||
};
|
||||
|
||||
AreaEval ae = createAreaEval("A1:A4", values);
|
||||
|
||||
|
||||
AreaEval ae = EvalFactory.createAreaEval("A1:A4", values);
|
||||
|
||||
// Note String comparisons are case insensitive
|
||||
confirmInt(2, invokeMatch(BoolEval.FALSE, ae, MATCH_LARGEST_LTE));
|
||||
confirmInt(1, invokeMatch(BoolEval.FALSE, ae, MATCH_EXACT));
|
||||
confirmInt(4, invokeMatch(BoolEval.TRUE, ae, MATCH_LARGEST_LTE));
|
||||
confirmInt(3, invokeMatch(BoolEval.TRUE, ae, MATCH_EXACT));
|
||||
}
|
||||
|
||||
|
||||
public void testHeterogeneous() {
|
||||
|
||||
|
||||
ValueEval[] values = {
|
||||
new NumberEval(4),
|
||||
BoolEval.FALSE,
|
||||
new NumberEval(4),
|
||||
BoolEval.FALSE,
|
||||
new NumberEval(5),
|
||||
new StringEval("Albert"),
|
||||
BoolEval.FALSE,
|
||||
BoolEval.TRUE,
|
||||
new NumberEval(10),
|
||||
new StringEval("Charles"),
|
||||
new StringEval("Ed"),
|
||||
new NumberEval(10),
|
||||
new NumberEval(25),
|
||||
BoolEval.TRUE,
|
||||
new StringEval("Ed"),
|
||||
new StringEval("Albert"),
|
||||
BoolEval.FALSE,
|
||||
BoolEval.TRUE,
|
||||
new NumberEval(10),
|
||||
new StringEval("Charles"),
|
||||
new StringEval("Ed"),
|
||||
new NumberEval(10),
|
||||
new NumberEval(25),
|
||||
BoolEval.TRUE,
|
||||
new StringEval("Ed"),
|
||||
};
|
||||
|
||||
AreaEval ae = createAreaEval("A1:A13", values);
|
||||
|
||||
|
||||
AreaEval ae = EvalFactory.createAreaEval("A1:A13", values);
|
||||
|
||||
assertEquals(ErrorEval.NA, invokeMatch(new StringEval("Aaron"), ae, MATCH_LARGEST_LTE));
|
||||
|
||||
|
||||
confirmInt(5, invokeMatch(BoolEval.FALSE, ae, MATCH_LARGEST_LTE));
|
||||
confirmInt(2, invokeMatch(BoolEval.FALSE, ae, MATCH_EXACT));
|
||||
confirmInt(3, invokeMatch(new NumberEval(5), ae, MATCH_LARGEST_LTE));
|
||||
confirmInt(3, invokeMatch(new NumberEval(5), ae, MATCH_EXACT));
|
||||
|
||||
|
||||
confirmInt(8, invokeMatch(new StringEval("CHARLES"), ae, MATCH_EXACT));
|
||||
|
||||
|
||||
confirmInt(4, invokeMatch(new StringEval("Ben"), ae, MATCH_LARGEST_LTE));
|
||||
|
||||
|
||||
confirmInt(13, invokeMatch(new StringEval("ED"), ae, MATCH_LARGEST_LTE));
|
||||
confirmInt(9, invokeMatch(new StringEval("ED"), ae, MATCH_EXACT));
|
||||
|
||||
|
||||
confirmInt(13, invokeMatch(new StringEval("Hugh"), ae, MATCH_LARGEST_LTE));
|
||||
assertEquals(ErrorEval.NA, invokeMatch(new StringEval("Hugh"), ae, MATCH_EXACT));
|
||||
|
||||
|
||||
confirmInt(11, invokeMatch(new NumberEval(30), ae, MATCH_LARGEST_LTE));
|
||||
confirmInt(12, invokeMatch(BoolEval.TRUE, ae, MATCH_LARGEST_LTE));
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Ensures that the match_type argument can be an <tt>AreaEval</tt>.<br/>
|
||||
* Bugzilla 44421
|
||||
*/
|
||||
public void testMatchArgTypeArea() {
|
||||
|
||||
ValueEval[] values = {
|
||||
new NumberEval(4),
|
||||
new NumberEval(5),
|
||||
new NumberEval(10),
|
||||
new NumberEval(10),
|
||||
new NumberEval(25),
|
||||
};
|
||||
|
||||
AreaEval ae = createAreaEval("A1:A5", values);
|
||||
|
||||
AreaEval matchAE = createAreaEval("C1:C1", new ValueEval[] { MATCH_LARGEST_LTE, });
|
||||
|
||||
ValueEval[] values = {
|
||||
new NumberEval(4),
|
||||
new NumberEval(5),
|
||||
new NumberEval(10),
|
||||
new NumberEval(10),
|
||||
new NumberEval(25),
|
||||
};
|
||||
|
||||
AreaEval ae = EvalFactory.createAreaEval("A1:A5", values);
|
||||
|
||||
AreaEval matchAE = EvalFactory.createAreaEval("C1:C1", new ValueEval[] { MATCH_LARGEST_LTE, });
|
||||
|
||||
try {
|
||||
confirmInt(4, invokeMatch(new NumberEval(10), ae, matchAE));
|
||||
} catch (RuntimeException e) {
|
||||
if(e.getMessage().startsWith("Unexpected match_type type")) {
|
||||
// identified bug 44421
|
||||
// identified bug 44421
|
||||
fail(e.getMessage());
|
||||
}
|
||||
// some other error ??
|
||||
|
@ -20,6 +20,8 @@
|
||||
*/
|
||||
package org.apache.poi.hssf.record.formula.functions;
|
||||
|
||||
import org.apache.poi.hssf.record.formula.functions.XYNumericFunction.Accumulator;
|
||||
|
||||
|
||||
/**
|
||||
* @author Amol S. Deshmukh < amolweb at ya hoo dot com >
|
||||
@ -566,99 +568,99 @@ public class TestMathX extends AbstractNumericTestCase {
|
||||
}
|
||||
|
||||
public void testSumx2my2() {
|
||||
double d = 0;
|
||||
double[] xarr = null;
|
||||
double[] yarr = null;
|
||||
|
||||
xarr = new double[]{1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
|
||||
yarr = new double[]{0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
|
||||
d = MathX.sumx2my2(xarr, yarr);
|
||||
assertEquals("sumx2my2 ", 100, d);
|
||||
confirmSumx2my2(xarr, yarr, 100);
|
||||
|
||||
xarr = new double[]{-1, -2, -3, -4, -5, -6, -7, -8, -9, -10};
|
||||
yarr = new double[]{0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
|
||||
d = MathX.sumx2my2(xarr, yarr);
|
||||
assertEquals("sumx2my2 ", 100, d);
|
||||
confirmSumx2my2(xarr, yarr, 100);
|
||||
|
||||
xarr = new double[]{0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
|
||||
yarr = new double[]{1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
|
||||
d = MathX.sumx2my2(xarr, yarr);
|
||||
assertEquals("sumx2my2 ", -100, d);
|
||||
confirmSumx2my2(xarr, yarr, -100);
|
||||
|
||||
xarr = new double[]{10};
|
||||
yarr = new double[]{9};
|
||||
d = MathX.sumx2my2(xarr, yarr);
|
||||
assertEquals("sumx2my2 ", 19, d);
|
||||
confirmSumx2my2(xarr, yarr, 19);
|
||||
|
||||
xarr = new double[]{1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
|
||||
yarr = new double[]{1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
|
||||
d = MathX.sumx2my2(xarr, yarr);
|
||||
assertEquals("sumx2my2 ", 0, d);
|
||||
|
||||
confirmSumx2my2(xarr, yarr, 0);
|
||||
}
|
||||
|
||||
public void testSumx2py2() {
|
||||
double d = 0;
|
||||
double[] xarr = null;
|
||||
double[] yarr = null;
|
||||
|
||||
xarr = new double[]{1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
|
||||
yarr = new double[]{0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
|
||||
d = MathX.sumx2py2(xarr, yarr);
|
||||
assertEquals("sumx2py2 ", 670, d);
|
||||
confirmSumx2py2(xarr, yarr, 670);
|
||||
|
||||
xarr = new double[]{-1, -2, -3, -4, -5, -6, -7, -8, -9, -10};
|
||||
yarr = new double[]{0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
|
||||
d = MathX.sumx2py2(xarr, yarr);
|
||||
assertEquals("sumx2py2 ", 670, d);
|
||||
confirmSumx2py2(xarr, yarr, 670);
|
||||
|
||||
xarr = new double[]{0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
|
||||
yarr = new double[]{1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
|
||||
d = MathX.sumx2py2(xarr, yarr);
|
||||
assertEquals("sumx2py2 ", 670, d);
|
||||
confirmSumx2py2(xarr, yarr, 670);
|
||||
|
||||
xarr = new double[]{10};
|
||||
yarr = new double[]{9};
|
||||
d = MathX.sumx2py2(xarr, yarr);
|
||||
assertEquals("sumx2py2 ", 181, d);
|
||||
confirmSumx2py2(xarr, yarr, 181);
|
||||
|
||||
xarr = new double[]{1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
|
||||
yarr = new double[]{1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
|
||||
d = MathX.sumx2py2(xarr, yarr);
|
||||
assertEquals("sumx2py2 ", 770, d);
|
||||
confirmSumx2py2(xarr, yarr, 770);
|
||||
}
|
||||
|
||||
public void testSumxmy2() {
|
||||
double d = 0;
|
||||
double[] xarr = null;
|
||||
double[] yarr = null;
|
||||
|
||||
xarr = new double[]{1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
|
||||
yarr = new double[]{0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
|
||||
d = MathX.sumxmy2(xarr, yarr);
|
||||
assertEquals("sumxmy2 ", 10, d);
|
||||
confirmSumxmy2(xarr, yarr, 10);
|
||||
|
||||
xarr = new double[]{-1, -2, -3, -4, -5, -6, -7, -8, -9, -10};
|
||||
yarr = new double[]{0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
|
||||
d = MathX.sumxmy2(xarr, yarr);
|
||||
assertEquals("sumxmy2 ", 1330, d);
|
||||
confirmSumxmy2(xarr, yarr, 1330);
|
||||
|
||||
xarr = new double[]{0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
|
||||
yarr = new double[]{1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
|
||||
d = MathX.sumxmy2(xarr, yarr);
|
||||
assertEquals("sumxmy2 ", 10, d);
|
||||
confirmSumxmy2(xarr, yarr, 10);
|
||||
|
||||
xarr = new double[]{10};
|
||||
yarr = new double[]{9};
|
||||
d = MathX.sumxmy2(xarr, yarr);
|
||||
assertEquals("sumxmy2 ", 1, d);
|
||||
confirmSumxmy2(xarr, yarr, 1);
|
||||
|
||||
xarr = new double[]{1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
|
||||
yarr = new double[]{1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
|
||||
d = MathX.sumxmy2(xarr, yarr);
|
||||
assertEquals("sumxmy2 ", 0, d);
|
||||
confirmSumxmy2(xarr, yarr, 0);
|
||||
}
|
||||
|
||||
private static void confirmSumx2my2(double[] xarr, double[] yarr, double expectedResult) {
|
||||
confirmXY(new Sumx2my2().createAccumulator(), xarr, yarr, expectedResult);
|
||||
}
|
||||
private static void confirmSumx2py2(double[] xarr, double[] yarr, double expectedResult) {
|
||||
confirmXY(new Sumx2py2().createAccumulator(), xarr, yarr, expectedResult);
|
||||
}
|
||||
private static void confirmSumxmy2(double[] xarr, double[] yarr, double expectedResult) {
|
||||
confirmXY(new Sumxmy2().createAccumulator(), xarr, yarr, expectedResult);
|
||||
}
|
||||
|
||||
private static void confirmXY(Accumulator acc, double[] xarr, double[] yarr,
|
||||
double expectedResult) {
|
||||
double result = 0.0;
|
||||
for (int i = 0; i < xarr.length; i++) {
|
||||
result += acc.accumulate(xarr[i], yarr[i]);
|
||||
}
|
||||
assertEquals(expectedResult, result, 0.0);
|
||||
}
|
||||
|
||||
public void testRound() {
|
||||
double d = 0;
|
||||
int p = 0;
|
||||
|
@ -17,29 +17,25 @@
|
||||
|
||||
package org.apache.poi.hssf.record.formula.functions;
|
||||
|
||||
import org.apache.poi.hssf.record.formula.AreaPtg;
|
||||
import org.apache.poi.hssf.record.formula.RefPtg;
|
||||
import org.apache.poi.hssf.record.formula.eval.Area2DEval;
|
||||
import junit.framework.TestCase;
|
||||
|
||||
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.NumberEval;
|
||||
import org.apache.poi.hssf.record.formula.eval.Ref2DEval;
|
||||
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 junit.framework.TestCase;
|
||||
/**
|
||||
* Tests for Excel function MID()
|
||||
*
|
||||
*
|
||||
* @author Josh Micich
|
||||
*/
|
||||
public final class TestMid extends TestCase {
|
||||
|
||||
|
||||
|
||||
private static Eval invokeMid(Eval text, Eval startPos, Eval numChars) {
|
||||
Eval[] args = new Eval[] { text, startPos, numChars, };
|
||||
return new Mid().evaluate(args, -1, (short)-1);
|
||||
@ -56,28 +52,28 @@ public final class TestMid extends TestCase {
|
||||
assertEquals(ErrorEval.class, result.getClass());
|
||||
assertEquals(expectedError.getErrorCode(), ((ErrorEval)result).getErrorCode());
|
||||
}
|
||||
|
||||
|
||||
public void testBasic() {
|
||||
|
||||
|
||||
confirmMid(new StringEval("galactic"), new NumberEval(3), new NumberEval(4), "lact");
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Valid cases where args are not precisely (string, int, int) but can be resolved OK.
|
||||
*/
|
||||
public void testUnusualArgs() {
|
||||
// startPos with fractional digits
|
||||
confirmMid(new StringEval("galactic"), new NumberEval(3.1), new NumberEval(4), "lact");
|
||||
|
||||
|
||||
// string startPos
|
||||
confirmMid(new StringEval("galactic"), new StringEval("3"), new NumberEval(4), "lact");
|
||||
|
||||
// text (first) arg type is number, other args are strings with fractional digits
|
||||
|
||||
// text (first) arg type is number, other args are strings with fractional digits
|
||||
confirmMid(new NumberEval(123456), new StringEval("3.1"), new StringEval("2.9"), "34");
|
||||
|
||||
|
||||
// startPos is 1x1 area ref, numChars is cell ref
|
||||
AreaEval aeStart = new Area2DEval(new AreaPtg("A1:A1"), new ValueEval[] { new NumberEval(2), } );
|
||||
RefEval reNumChars = new Ref2DEval(new RefPtg("B1"), new NumberEval(3));
|
||||
AreaEval aeStart = EvalFactory.createAreaEval("A1:A1", new ValueEval[] { new NumberEval(2), } );
|
||||
RefEval reNumChars = EvalFactory.createRefEval("B1", new NumberEval(3));
|
||||
confirmMid(new StringEval("galactic"), aeStart, reNumChars, "ala");
|
||||
|
||||
confirmMid(new StringEval("galactic"), new NumberEval(3.1), BlankEval.INSTANCE, "");
|
||||
@ -85,7 +81,7 @@ public final class TestMid extends TestCase {
|
||||
confirmMid(new StringEval("galactic"), new NumberEval(3), BoolEval.FALSE, "");
|
||||
confirmMid(new StringEval("galactic"), new NumberEval(3), BoolEval.TRUE, "l");
|
||||
confirmMid(BlankEval.INSTANCE, new NumberEval(3), BoolEval.TRUE, "");
|
||||
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
@ -93,7 +89,7 @@ public final class TestMid extends TestCase {
|
||||
*/
|
||||
public void testExtremes() {
|
||||
confirmMid(new StringEval("galactic"), new NumberEval(4), new NumberEval(400), "actic");
|
||||
|
||||
|
||||
confirmMid(new StringEval("galactic"), new NumberEval(30), new NumberEval(4), "");
|
||||
confirmMid(new StringEval("galactic"), new NumberEval(3), new NumberEval(0), "");
|
||||
}
|
||||
@ -106,9 +102,9 @@ public final class TestMid extends TestCase {
|
||||
confirmMid(new StringEval("galactic"), ErrorEval.NAME_INVALID, new NumberEval(4), ErrorEval.NAME_INVALID);
|
||||
confirmMid(new StringEval("galactic"), new NumberEval(3), ErrorEval.NAME_INVALID, ErrorEval.NAME_INVALID);
|
||||
confirmMid(new StringEval("galactic"), ErrorEval.DIV_ZERO, ErrorEval.NAME_INVALID, ErrorEval.DIV_ZERO);
|
||||
|
||||
|
||||
confirmMid(new StringEval("galactic"), BlankEval.INSTANCE, new NumberEval(3.1), ErrorEval.VALUE_INVALID);
|
||||
|
||||
|
||||
confirmMid(new StringEval("galactic"), new NumberEval(0), new NumberEval(4), ErrorEval.VALUE_INVALID);
|
||||
confirmMid(new StringEval("galactic"), new NumberEval(1), new NumberEval(-1), ErrorEval.VALUE_INVALID);
|
||||
}
|
||||
|
@ -17,18 +17,16 @@
|
||||
|
||||
package org.apache.poi.hssf.record.formula.functions;
|
||||
|
||||
import org.apache.poi.hssf.record.formula.RefPtg;
|
||||
import junit.framework.TestCase;
|
||||
|
||||
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.NumericValueEval;
|
||||
import org.apache.poi.hssf.record.formula.eval.Ref2DEval;
|
||||
import org.apache.poi.hssf.record.formula.eval.RefEval;
|
||||
import org.apache.poi.hssf.record.formula.eval.ValueEval;
|
||||
|
||||
import junit.framework.TestCase;
|
||||
|
||||
/**
|
||||
* Test cases for SUMPRODUCT()
|
||||
*
|
||||
@ -50,7 +48,7 @@ public final class TestSumproduct extends TestCase {
|
||||
|
||||
public void testScalarSimple() {
|
||||
|
||||
RefEval refEval = new Ref2DEval(new RefPtg("A1"), new NumberEval(3));
|
||||
RefEval refEval = EvalFactory.createRefEval("A1", new NumberEval(3));
|
||||
Eval[] args = {
|
||||
refEval,
|
||||
new NumberEval(2),
|
||||
@ -113,7 +111,6 @@ public final class TestSumproduct extends TestCase {
|
||||
};
|
||||
AreaEval aeA = EvalFactory.createAreaEval("A1:A2", aValues);
|
||||
AreaEval aeB = EvalFactory.createAreaEval("B1:B2", new ValueEval[2]);
|
||||
aeB.getValues()[1] = ErrorEval.REF_INVALID;
|
||||
|
||||
Eval[] args = { aeA, aeB, };
|
||||
assertEquals(ErrorEval.REF_INVALID, invokeSumproduct(args));
|
||||
|
@ -17,18 +17,16 @@
|
||||
|
||||
package org.apache.poi.hssf.record.formula.functions;
|
||||
|
||||
import org.apache.poi.hssf.record.formula.RefPtg;
|
||||
import junit.framework.TestCase;
|
||||
|
||||
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.NumberEval;
|
||||
import org.apache.poi.hssf.record.formula.eval.Ref2DEval;
|
||||
import org.apache.poi.hssf.record.formula.eval.StringEval;
|
||||
import org.apache.poi.hssf.record.formula.eval.ValueEval;
|
||||
|
||||
import junit.framework.TestCase;
|
||||
|
||||
/**
|
||||
* Test cases for Excel function T()
|
||||
*
|
||||
@ -50,7 +48,7 @@ public final class TestTFunc extends TestCase {
|
||||
* where cell A1 has the specified innerValue
|
||||
*/
|
||||
private Eval invokeTWithReference(ValueEval innerValue) {
|
||||
Eval arg = new Ref2DEval(new RefPtg((short)1, (short)1, false, false), innerValue);
|
||||
Eval arg = EvalFactory.createRefEval("$B$2", innerValue);
|
||||
return invokeT(arg);
|
||||
}
|
||||
|
||||
|
@ -19,8 +19,6 @@ package org.apache.poi.hssf.record.formula.functions;
|
||||
|
||||
import junit.framework.TestCase;
|
||||
|
||||
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.ErrorEval;
|
||||
import org.apache.poi.hssf.record.formula.eval.Eval;
|
||||
import org.apache.poi.hssf.record.formula.eval.NumberEval;
|
||||
@ -100,7 +98,7 @@ public final class TestXYNumericFunction extends TestCase {
|
||||
|
||||
private static ValueEval createAreaEval(ValueEval[] values) {
|
||||
String refStr = "A1:A" + values.length;
|
||||
return new Area2DEval(new AreaPtg(refStr), values);
|
||||
return EvalFactory.createAreaEval(refStr, values);
|
||||
}
|
||||
|
||||
public void testErrors() {
|
||||
|
@ -24,8 +24,8 @@ import java.io.IOException;
|
||||
import junit.framework.TestCase;
|
||||
|
||||
import org.apache.poi.hssf.HSSFTestDataSamples;
|
||||
import org.apache.poi.hssf.util.AreaReference;
|
||||
import org.apache.poi.hssf.util.CellReference;
|
||||
import org.apache.poi.ss.util.AreaReference;
|
||||
import org.apache.poi.ss.util.CellReference;
|
||||
|
||||
/**
|
||||
*
|
||||
|
@ -34,6 +34,8 @@ import org.apache.poi.hssf.usermodel.HSSFName;
|
||||
import org.apache.poi.hssf.usermodel.HSSFRow;
|
||||
import org.apache.poi.hssf.usermodel.HSSFSheet;
|
||||
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
|
||||
import org.apache.poi.ss.util.AreaReference;
|
||||
import org.apache.poi.ss.util.CellReference;
|
||||
/**
|
||||
*
|
||||
*/
|
||||
|
@ -20,7 +20,8 @@ package org.apache.poi.hssf.util;
|
||||
|
||||
import junit.framework.TestCase;
|
||||
|
||||
import org.apache.poi.hssf.util.CellReference.NameType;
|
||||
import org.apache.poi.ss.util.CellReference;
|
||||
import org.apache.poi.ss.util.CellReference.NameType;
|
||||
|
||||
|
||||
public final class TestCellReference extends TestCase {
|
||||
|
Loading…
Reference in New Issue
Block a user