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-690738,690740-690760,690762-690771,690773-690824,690826-690834,690838-691016,691018-691179,691181,691183-692908 via svnmerge from
https://svn.apache.org/repos/asf/poi/trunk ........ r691533 | yegor | 2008-09-03 09:04:07 +0100 (Wed, 03 Sep 2008) | 1 line fixed bug #45728: SlideShow.reorderSlide didn't work properly ........ r691687 | josh | 2008-09-03 18:03:02 +0100 (Wed, 03 Sep 2008) | 1 line Fixed ArrayPtg.toString to not crash when partially initialised ........ r691740 | josh | 2008-09-03 20:22:53 +0100 (Wed, 03 Sep 2008) | 1 line Initial work on bug 45720 - copy 'FilterDatabase' named record when cloning sheets. Some clean-up in NameRecord. ........ r692239 | josh | 2008-09-04 21:58:37 +0100 (Thu, 04 Sep 2008) | 1 line Fixed 2 small bugs in RelationalOperationEval (added junits). Refactored hierarchy. ........ r692241 | josh | 2008-09-04 22:01:48 +0100 (Thu, 04 Sep 2008) | 1 line Fix unused import (correction to r692239) ........ r692243 | josh | 2008-09-04 22:05:50 +0100 (Thu, 04 Sep 2008) | 1 line Fixed compiler warnings, linked junit test to suite ........ r692255 | josh | 2008-09-04 22:32:17 +0100 (Thu, 04 Sep 2008) | 1 line Made HSSFFormulaEvaluator capable of handling simple named ranges ........ r692300 | josh | 2008-09-05 00:16:15 +0100 (Fri, 05 Sep 2008) | 1 line Fix for bug 45376 - added caching to HSSFFormulaEvaluator ........ r692506 | josh | 2008-09-05 19:22:30 +0100 (Fri, 05 Sep 2008) | 1 line Minor fixes for numeric operators - junit added. Some refactoring. ........ r692538 | josh | 2008-09-05 21:38:51 +0100 (Fri, 05 Sep 2008) | 1 line Modified formula evaluator to handle whole column refs ........ r692541 | josh | 2008-09-05 21:43:37 +0100 (Fri, 05 Sep 2008) | 1 line reverted changes accidentally submitted with r692538 ........ r692612 | josh | 2008-09-06 06:30:31 +0100 (Sat, 06 Sep 2008) | 1 line Fixes for special cases of lookup functions (test cases added) ........ r692614 | josh | 2008-09-06 07:04:01 +0100 (Sat, 06 Sep 2008) | 1 line Minor fixes to YEARFRAC(). Added ISEVEN() and ISODD(). Added test cases. ........ r692893 | yegor | 2008-09-07 17:30:35 +0100 (Sun, 07 Sep 2008) | 1 line fixed bug #45720: cloneSheet breaks autofilters. ........ git-svn-id: https://svn.apache.org/repos/asf/poi/branches/ooxml@692932 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
parent
2a02163d66
commit
e6ec8e2601
@ -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="fix">45720 Fixed HSSFWorkbook.cloneSheet to correctly clone sheets with drawings</action>
|
||||
<action dev="POI-DEVELOPERS" type="fix">45728 Fix for SlideShow.reorderSlide in HSLF</action>
|
||||
<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>
|
||||
|
@ -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="fix">45720 Fixed HSSFWorkbook.cloneSheet to correctly clone sheets with drawings</action>
|
||||
<action dev="POI-DEVELOPERS" type="fix">45728 Fix for SlideShow.reorderSlide in HSLF</action>
|
||||
<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>
|
||||
|
@ -235,4 +235,21 @@ public class EscherContainerRecord extends EscherRecord
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Recursively find records with the specified record ID
|
||||
*
|
||||
* @param out - list to store found records
|
||||
*/
|
||||
public void getRecordsById(short recordId, List out){
|
||||
for(Iterator it = childRecords.iterator(); it.hasNext();) {
|
||||
Object er = it.next();
|
||||
if(er instanceof EscherContainerRecord) {
|
||||
EscherContainerRecord c = (EscherContainerRecord)er;
|
||||
c.getRecordsById(recordId, out );
|
||||
} else if (er instanceof EscherSpRecord){
|
||||
out.add(er);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -67,6 +67,17 @@ public class DrawingManager2
|
||||
* @return a new shape id.
|
||||
*/
|
||||
public int allocateShapeId(short drawingGroupId)
|
||||
{
|
||||
EscherDgRecord dg = getDrawingGroup(drawingGroupId);
|
||||
return allocateShapeId(drawingGroupId, dg);
|
||||
}
|
||||
|
||||
/**
|
||||
* Allocates new shape id for the new drawing group id.
|
||||
*
|
||||
* @return a new shape id.
|
||||
*/
|
||||
public int allocateShapeId(short drawingGroupId, EscherDgRecord dg)
|
||||
{
|
||||
dgg.setNumShapesSaved( dgg.getNumShapesSaved() + 1 );
|
||||
|
||||
@ -78,7 +89,6 @@ public class DrawingManager2
|
||||
{
|
||||
int result = c.getNumShapeIdsUsed() + (1024 * (i+1));
|
||||
c.incrementShapeId();
|
||||
EscherDgRecord dg = getDrawingGroup(drawingGroupId);
|
||||
dg.setNumShapes( dg.getNumShapes() + 1 );
|
||||
dg.setLastMSOSPID( result );
|
||||
if (result >= dgg.getShapeIdMax())
|
||||
@ -90,7 +100,6 @@ public class DrawingManager2
|
||||
// Create new cluster
|
||||
dgg.addCluster( drawingGroupId, 0 );
|
||||
dgg.getFileIdClusters()[dgg.getFileIdClusters().length-1].incrementShapeId();
|
||||
EscherDgRecord dg = getDrawingGroup(drawingGroupId);
|
||||
dg.setNumShapes( dg.getNumShapes() + 1 );
|
||||
int result = (1024 * dgg.getFileIdClusters().length);
|
||||
dg.setLastMSOSPID( result );
|
||||
@ -98,7 +107,6 @@ public class DrawingManager2
|
||||
dgg.setShapeIdMax( result + 1 );
|
||||
return result;
|
||||
}
|
||||
|
||||
//////////// Non-public methods /////////////
|
||||
|
||||
/**
|
||||
|
@ -22,57 +22,8 @@ import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
|
||||
import org.apache.poi.ddf.EscherBSERecord;
|
||||
import org.apache.poi.ddf.EscherBoolProperty;
|
||||
import org.apache.poi.ddf.EscherContainerRecord;
|
||||
import org.apache.poi.ddf.EscherDggRecord;
|
||||
import org.apache.poi.ddf.EscherOptRecord;
|
||||
import org.apache.poi.ddf.EscherProperties;
|
||||
import org.apache.poi.ddf.EscherRGBProperty;
|
||||
import org.apache.poi.ddf.EscherRecord;
|
||||
import org.apache.poi.ddf.EscherSplitMenuColorsRecord;
|
||||
import org.apache.poi.hssf.record.BOFRecord;
|
||||
import org.apache.poi.hssf.record.BackupRecord;
|
||||
import org.apache.poi.hssf.record.BookBoolRecord;
|
||||
import org.apache.poi.hssf.record.BoundSheetRecord;
|
||||
import org.apache.poi.hssf.record.CodepageRecord;
|
||||
import org.apache.poi.hssf.record.CountryRecord;
|
||||
import org.apache.poi.hssf.record.DSFRecord;
|
||||
import org.apache.poi.hssf.record.DateWindow1904Record;
|
||||
import org.apache.poi.hssf.record.DrawingGroupRecord;
|
||||
import org.apache.poi.hssf.record.EOFRecord;
|
||||
import org.apache.poi.hssf.record.ExtSSTRecord;
|
||||
import org.apache.poi.hssf.record.ExtendedFormatRecord;
|
||||
import org.apache.poi.hssf.record.ExternSheetRecord;
|
||||
import org.apache.poi.hssf.record.FileSharingRecord;
|
||||
import org.apache.poi.hssf.record.FnGroupCountRecord;
|
||||
import org.apache.poi.hssf.record.FontRecord;
|
||||
import org.apache.poi.hssf.record.FormatRecord;
|
||||
import org.apache.poi.hssf.record.HideObjRecord;
|
||||
import org.apache.poi.hssf.record.HyperlinkRecord;
|
||||
import org.apache.poi.hssf.record.InterfaceEndRecord;
|
||||
import org.apache.poi.hssf.record.InterfaceHdrRecord;
|
||||
import org.apache.poi.hssf.record.MMSRecord;
|
||||
import org.apache.poi.hssf.record.NameRecord;
|
||||
import org.apache.poi.hssf.record.PaletteRecord;
|
||||
import org.apache.poi.hssf.record.PasswordRecord;
|
||||
import org.apache.poi.hssf.record.PasswordRev4Record;
|
||||
import org.apache.poi.hssf.record.PrecisionRecord;
|
||||
import org.apache.poi.hssf.record.ProtectRecord;
|
||||
import org.apache.poi.hssf.record.ProtectionRev4Record;
|
||||
import org.apache.poi.hssf.record.RecalcIdRecord;
|
||||
import org.apache.poi.hssf.record.Record;
|
||||
import org.apache.poi.hssf.record.RefreshAllRecord;
|
||||
import org.apache.poi.hssf.record.SSTRecord;
|
||||
import org.apache.poi.hssf.record.StyleRecord;
|
||||
import org.apache.poi.hssf.record.SupBookRecord;
|
||||
import org.apache.poi.hssf.record.TabIdRecord;
|
||||
import org.apache.poi.hssf.record.UnicodeString;
|
||||
import org.apache.poi.hssf.record.UseSelFSRecord;
|
||||
import org.apache.poi.hssf.record.WindowOneRecord;
|
||||
import org.apache.poi.hssf.record.WindowProtectRecord;
|
||||
import org.apache.poi.hssf.record.WriteAccessRecord;
|
||||
import org.apache.poi.hssf.record.WriteProtectRecord;
|
||||
import org.apache.poi.ddf.*;
|
||||
import org.apache.poi.hssf.record.*;
|
||||
import org.apache.poi.hssf.record.formula.NameXPtg;
|
||||
import org.apache.poi.hssf.util.HSSFColor;
|
||||
import org.apache.poi.hssf.util.SheetReferences;
|
||||
@ -2206,17 +2157,17 @@ public final class Workbook implements Model {
|
||||
// contains a EscherDggRecord
|
||||
for(Iterator rit = records.iterator(); rit.hasNext();) {
|
||||
Record r = (Record)rit.next();
|
||||
|
||||
|
||||
if(r instanceof DrawingGroupRecord) {
|
||||
DrawingGroupRecord dg = (DrawingGroupRecord)r;
|
||||
dg.processChildRecords();
|
||||
|
||||
|
||||
EscherContainerRecord cr =
|
||||
dg.getEscherContainer();
|
||||
if(cr == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
EscherDggRecord dgg = null;
|
||||
for(Iterator it = cr.getChildRecords().iterator(); it.hasNext();) {
|
||||
Object er = it.next();
|
||||
@ -2224,7 +2175,7 @@ public final class Workbook implements Model {
|
||||
dgg = (EscherDggRecord)er;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if(dgg != null) {
|
||||
drawingManager = new DrawingManager2(dgg);
|
||||
return;
|
||||
@ -2234,7 +2185,7 @@ public final class Workbook implements Model {
|
||||
|
||||
// Look for the DrawingGroup record
|
||||
int dgLoc = findFirstRecordLocBySid(DrawingGroupRecord.sid);
|
||||
|
||||
|
||||
// If there is one, does it have a EscherDggRecord?
|
||||
if(dgLoc != -1) {
|
||||
DrawingGroupRecord dg =
|
||||
@ -2246,7 +2197,7 @@ public final class Workbook implements Model {
|
||||
dgg = (EscherDggRecord)er;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if(dgg != null) {
|
||||
drawingManager = new DrawingManager2(dgg);
|
||||
}
|
||||
@ -2455,4 +2406,54 @@ public final class Workbook implements Model {
|
||||
public NameXPtg getNameXPtg(String name) {
|
||||
return getOrCreateLinkTable().getNameXPtg(name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the cloned sheet has drawings. If yes, then allocate a new drawing group ID and
|
||||
* re-generate shape IDs
|
||||
*
|
||||
* @param sheet the cloned sheet
|
||||
*/
|
||||
public void cloneDrawings(Sheet sheet){
|
||||
|
||||
findDrawingGroup();
|
||||
|
||||
if(drawingManager == null) {
|
||||
//this workbook does not have drawings
|
||||
return;
|
||||
}
|
||||
|
||||
//check if the cloned sheet has drawings
|
||||
int aggLoc = sheet.aggregateDrawingRecords(drawingManager, false);
|
||||
if(aggLoc != -1) {
|
||||
EscherAggregate agg = (EscherAggregate) sheet.findFirstRecordBySid(EscherAggregate.sid);
|
||||
|
||||
EscherDggRecord dgg = drawingManager.getDgg();
|
||||
|
||||
//register a new drawing group for the cloned sheet
|
||||
int dgId = drawingManager.findNewDrawingGroupId();
|
||||
dgg.addCluster( dgId, 0 );
|
||||
dgg.setDrawingsSaved(dgg.getDrawingsSaved() + 1);
|
||||
|
||||
EscherDgRecord dg = null;
|
||||
for(Iterator it = agg.getEscherContainer().getChildRecords().iterator(); it.hasNext();) {
|
||||
Object er = it.next();
|
||||
if(er instanceof EscherDgRecord) {
|
||||
dg = (EscherDgRecord)er;
|
||||
//update id of the drawing in the cloned sheet
|
||||
dg.setOptions( (short) ( dgId << 4 ) );
|
||||
} else if (er instanceof EscherContainerRecord){
|
||||
//recursively find shape records and re-generate shapeId
|
||||
ArrayList spRecords = new ArrayList();
|
||||
EscherContainerRecord cp = (EscherContainerRecord)er;
|
||||
cp.getRecordsById(EscherSpRecord.RECORD_ID, spRecords);
|
||||
for(Iterator spIt = spRecords.iterator(); spIt.hasNext();) {
|
||||
EscherSpRecord sp = (EscherSpRecord)spIt.next();
|
||||
int shapeId = drawingManager.allocateShapeId((short)dgId, dg);
|
||||
sp.setShapeId(shapeId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -17,9 +17,8 @@
|
||||
|
||||
package org.apache.poi.hssf.record;
|
||||
|
||||
import java.util.Iterator;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Stack;
|
||||
|
||||
import org.apache.poi.hssf.model.FormulaParser;
|
||||
import org.apache.poi.hssf.record.formula.Area3DPtg;
|
||||
@ -44,51 +43,33 @@ import org.apache.poi.util.StringUtil;
|
||||
*/
|
||||
public final class NameRecord extends Record {
|
||||
public final static short sid = 0x0018;
|
||||
/**Included for completeness sake, not implemented
|
||||
*/
|
||||
public final static byte BUILTIN_CONSOLIDATE_AREA = (byte)1;
|
||||
|
||||
/**Included for completeness sake, not implemented
|
||||
*/
|
||||
public final static byte BUILTIN_AUTO_OPEN = (byte)2;
|
||||
/**Included for completeness sake, not implemented */
|
||||
public final static byte BUILTIN_CONSOLIDATE_AREA = 1;
|
||||
/**Included for completeness sake, not implemented */
|
||||
public final static byte BUILTIN_AUTO_OPEN = 2;
|
||||
/**Included for completeness sake, not implemented */
|
||||
public final static byte BUILTIN_AUTO_CLOSE = 3;
|
||||
/**Included for completeness sake, not implemented */
|
||||
public final static byte BUILTIN_DATABASE = 4;
|
||||
/**Included for completeness sake, not implemented */
|
||||
public final static byte BUILTIN_CRITERIA = 5;
|
||||
|
||||
/**Included for completeness sake, not implemented
|
||||
*/
|
||||
public final static byte BUILTIN_AUTO_CLOSE = (byte)3;
|
||||
public final static byte BUILTIN_PRINT_AREA = 6;
|
||||
public final static byte BUILTIN_PRINT_TITLE = 7;
|
||||
|
||||
/**Included for completeness sake, not implemented
|
||||
*/
|
||||
public final static byte BUILTIN_DATABASE = (byte)4;
|
||||
/**Included for completeness sake, not implemented */
|
||||
public final static byte BUILTIN_RECORDER = 8;
|
||||
/**Included for completeness sake, not implemented */
|
||||
public final static byte BUILTIN_DATA_FORM = 9;
|
||||
/**Included for completeness sake, not implemented */
|
||||
public final static byte BUILTIN_AUTO_ACTIVATE = 10;
|
||||
/**Included for completeness sake, not implemented */
|
||||
public final static byte BUILTIN_AUTO_DEACTIVATE = 11;
|
||||
/**Included for completeness sake, not implemented */
|
||||
public final static byte BUILTIN_SHEET_TITLE = 12;
|
||||
|
||||
/**Included for completeness sake, not implemented
|
||||
*/
|
||||
public final static byte BUILTIN_CRITERIA = (byte)5;
|
||||
|
||||
public final static byte BUILTIN_PRINT_AREA = (byte)6;
|
||||
public final static byte BUILTIN_PRINT_TITLE = (byte)7;
|
||||
|
||||
/**Included for completeness sake, not implemented
|
||||
*/
|
||||
public final static byte BUILTIN_RECORDER = (byte)8;
|
||||
|
||||
/**Included for completeness sake, not implemented
|
||||
*/
|
||||
public final static byte BUILTIN_DATA_FORM = (byte)9;
|
||||
|
||||
/**Included for completeness sake, not implemented
|
||||
*/
|
||||
public final static byte BUILTIN_FILTER_DB = 13;
|
||||
|
||||
public final static byte BUILTIN_AUTO_ACTIVATE = (byte)10;
|
||||
|
||||
/**Included for completeness sake, not implemented
|
||||
*/
|
||||
|
||||
public final static byte BUILTIN_AUTO_DEACTIVATE = (byte)11;
|
||||
|
||||
/**Included for completeness sake, not implemented
|
||||
*/
|
||||
public final static byte BUILTIN_SHEET_TITLE = (byte)12;
|
||||
|
||||
private static final class Option {
|
||||
public static final int OPT_HIDDEN_NAME = 0x0001;
|
||||
public static final int OPT_FUNCTION_NAME = 0x0002;
|
||||
@ -98,22 +79,16 @@ public final class NameRecord extends Record {
|
||||
public static final int OPT_BUILTIN = 0x0020;
|
||||
public static final int OPT_BINDATA = 0x1000;
|
||||
}
|
||||
|
||||
|
||||
private short field_1_option_flag;
|
||||
private byte field_2_keyboard_shortcut;
|
||||
private byte field_3_length_name_text;
|
||||
private short field_4_length_name_definition;
|
||||
private short field_5_index_to_sheet; // unused: see field_6
|
||||
/** the one based sheet number. Zero if this is a global name */
|
||||
private int field_6_sheetNumber;
|
||||
private byte field_7_length_custom_menu;
|
||||
private byte field_8_length_description_text;
|
||||
private byte field_9_length_help_topic_text;
|
||||
private byte field_10_length_status_bar_text;
|
||||
private byte field_11_compressed_unicode_flag; // not documented
|
||||
private byte field_12_builtIn_name;
|
||||
private boolean field_11_nameIsMultibyte;
|
||||
private byte field_12_built_in_code;
|
||||
private String field_12_name_text;
|
||||
private Stack field_13_name_definition;
|
||||
private Ptg[] field_13_name_definition;
|
||||
private String field_14_custom_menu_text;
|
||||
private String field_15_description_text;
|
||||
private String field_16_help_topic_text;
|
||||
@ -122,13 +97,13 @@ public final class NameRecord extends Record {
|
||||
|
||||
/** Creates new NameRecord */
|
||||
public NameRecord() {
|
||||
field_13_name_definition = new Stack();
|
||||
field_13_name_definition = Ptg.EMPTY_PTG_ARRAY;
|
||||
|
||||
field_12_name_text = new String();
|
||||
field_14_custom_menu_text = new String();
|
||||
field_15_description_text = new String();
|
||||
field_16_help_topic_text = new String();
|
||||
field_17_status_bar_text = new String();
|
||||
field_12_name_text = "";
|
||||
field_14_custom_menu_text = "";
|
||||
field_15_description_text = "";
|
||||
field_16_help_topic_text = "";
|
||||
field_17_status_bar_text = "";
|
||||
}
|
||||
|
||||
/**
|
||||
@ -146,19 +121,10 @@ public final class NameRecord extends Record {
|
||||
*/
|
||||
public NameRecord(byte builtin, int sheetNumber)
|
||||
{
|
||||
this();
|
||||
this.field_12_builtIn_name = builtin;
|
||||
this.setOptionFlag((short)(this.field_1_option_flag | Option.OPT_BUILTIN));
|
||||
this.setNameTextLength((byte)1);
|
||||
this();
|
||||
field_12_built_in_code = builtin;
|
||||
setOptionFlag((short)(field_1_option_flag | Option.OPT_BUILTIN));
|
||||
field_6_sheetNumber = sheetNumber; //the extern sheets are set through references
|
||||
|
||||
//clearing these because they are not used with builtin records
|
||||
this.setCustomMenuLength((byte)0);
|
||||
this.setDescriptionTextLength((byte)0);
|
||||
this.setHelpTopicLength((byte)0);
|
||||
this.setStatusBarLength((byte)0);
|
||||
|
||||
|
||||
}
|
||||
|
||||
/** sets the option flag for the named range
|
||||
@ -176,34 +142,9 @@ public final class NameRecord extends Record {
|
||||
field_2_keyboard_shortcut = shortcut;
|
||||
}
|
||||
|
||||
/** sets the name of the named range length
|
||||
* @param length name length
|
||||
*/
|
||||
public void setNameTextLength(byte length){
|
||||
field_3_length_name_text = length;
|
||||
}
|
||||
|
||||
/** sets the definition (reference - formula) length
|
||||
* @param length defenition length
|
||||
*/
|
||||
public void setDefinitionTextLength(short length){
|
||||
field_4_length_name_definition = length;
|
||||
}
|
||||
|
||||
/** sets the index number to the extern sheet (thats is what writen in documentation
|
||||
* but as i saw , it works differently)
|
||||
* @param index extern sheet index
|
||||
*/
|
||||
public void setUnused(short index){
|
||||
field_5_index_to_sheet = index;
|
||||
|
||||
// field_6_equals_to_index_to_sheet is equal to field_5_index_to_sheet
|
||||
// field_6_equals_to_index_to_sheet = index;
|
||||
}
|
||||
|
||||
/**
|
||||
* For named ranges, and built-in names
|
||||
* @return the 1-based sheet number. Zero if this is a global name
|
||||
* @return the 1-based sheet number. Zero if this is a global name
|
||||
*/
|
||||
public int getSheetNumber()
|
||||
{
|
||||
@ -226,49 +167,12 @@ public final class NameRecord extends Record {
|
||||
}
|
||||
|
||||
|
||||
/** sets the custom menu length
|
||||
* @param length custom menu length
|
||||
*/
|
||||
public void setCustomMenuLength(byte length){
|
||||
field_7_length_custom_menu = length;
|
||||
}
|
||||
|
||||
/** sets the length of named range description
|
||||
* @param length description length
|
||||
*/
|
||||
public void setDescriptionTextLength(byte length){
|
||||
field_8_length_description_text = length;
|
||||
}
|
||||
|
||||
/** sets the help topic length
|
||||
* @param length help topic length
|
||||
*/
|
||||
public void setHelpTopicLength(byte length){
|
||||
field_9_length_help_topic_text = length;
|
||||
}
|
||||
|
||||
/** sets the length of the status bar text
|
||||
* @param length status bar text length
|
||||
*/
|
||||
public void setStatusBarLength(byte length){
|
||||
field_10_length_status_bar_text = length;
|
||||
}
|
||||
|
||||
/** sets the compressed unicode flag
|
||||
* @param flag unicode flag
|
||||
*/
|
||||
public void setCompressedUnicodeFlag(byte flag) {
|
||||
field_11_compressed_unicode_flag = flag;
|
||||
}
|
||||
|
||||
/** sets the name of the named range
|
||||
* @param name named range name
|
||||
*/
|
||||
public void setNameText(String name){
|
||||
field_12_name_text = name;
|
||||
setCompressedUnicodeFlag(
|
||||
StringUtil.hasMultibyte(name) ? (byte)1 : (byte)0
|
||||
);
|
||||
field_11_nameIsMultibyte = StringUtil.hasMultibyte(name);
|
||||
}
|
||||
|
||||
/** sets the custom menu text
|
||||
@ -313,72 +217,15 @@ public final class NameRecord extends Record {
|
||||
return field_2_keyboard_shortcut ;
|
||||
}
|
||||
|
||||
/**
|
||||
/**
|
||||
* gets the name length, in characters
|
||||
* @return name length
|
||||
*/
|
||||
public byte getNameTextLength(){
|
||||
return field_3_length_name_text;
|
||||
}
|
||||
|
||||
/**
|
||||
* gets the name length, in bytes
|
||||
* @return raw name length
|
||||
*/
|
||||
public byte getRawNameTextLength(){
|
||||
if( (field_11_compressed_unicode_flag & 0x01) == 1 ) {
|
||||
return (byte)(2 * field_3_length_name_text);
|
||||
private int getNameTextLength(){
|
||||
if (isBuiltInName()) {
|
||||
return 1;
|
||||
}
|
||||
return field_3_length_name_text;
|
||||
}
|
||||
|
||||
/** get the definition length
|
||||
* @return definition length
|
||||
*/
|
||||
public short getDefinitionLength(){
|
||||
return field_4_length_name_definition;
|
||||
}
|
||||
|
||||
/** gets the index to extern sheet
|
||||
* @return index to extern sheet
|
||||
*/
|
||||
public short getUnused(){
|
||||
return field_5_index_to_sheet;
|
||||
}
|
||||
|
||||
/** gets the custom menu length
|
||||
* @return custom menu length
|
||||
*/
|
||||
public byte getCustomMenuLength(){
|
||||
return field_7_length_custom_menu;
|
||||
}
|
||||
|
||||
/** gets the description text length
|
||||
* @return description text length
|
||||
*/
|
||||
public byte getDescriptionTextLength(){
|
||||
return field_8_length_description_text;
|
||||
}
|
||||
|
||||
/** gets the help topic length
|
||||
* @return help topic length
|
||||
*/
|
||||
public byte getHelpTopicLength(){
|
||||
return field_9_length_help_topic_text;
|
||||
}
|
||||
|
||||
/** get the status bar text length
|
||||
* @return satus bar length
|
||||
*/
|
||||
public byte getStatusBarLength(){
|
||||
return field_10_length_status_bar_text;
|
||||
}
|
||||
|
||||
/** gets the name compressed Unicode flag
|
||||
* @return compressed unicode flag
|
||||
*/
|
||||
public byte getCompressedUnicodeFlag() {
|
||||
return field_11_compressed_unicode_flag;
|
||||
return field_12_name_text.length();
|
||||
}
|
||||
|
||||
|
||||
@ -388,13 +235,26 @@ public final class NameRecord extends Record {
|
||||
public boolean isHiddenName() {
|
||||
return (field_1_option_flag & Option.OPT_HIDDEN_NAME) != 0;
|
||||
}
|
||||
public void setHidden(boolean b) {
|
||||
if (b) {
|
||||
field_1_option_flag |= Option.OPT_HIDDEN_NAME;
|
||||
} else {
|
||||
field_1_option_flag &= (~Option.OPT_HIDDEN_NAME);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* @return true if name is a function
|
||||
* @return <code>true</code> if name is a function
|
||||
*/
|
||||
public boolean isFunctionName() {
|
||||
return (field_1_option_flag & Option.OPT_FUNCTION_NAME) != 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return <code>true</code> if name has a formula (named range or defined value)
|
||||
*/
|
||||
public boolean hasFormula() {
|
||||
return field_1_option_flag == 0 && field_13_name_definition.length > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return true if name is a command
|
||||
@ -419,7 +279,7 @@ public final class NameRecord extends Record {
|
||||
*/
|
||||
public boolean isBuiltInName()
|
||||
{
|
||||
return ((this.field_1_option_flag & Option.OPT_BUILTIN) != 0);
|
||||
return ((field_1_option_flag & Option.OPT_BUILTIN) != 0);
|
||||
}
|
||||
|
||||
|
||||
@ -428,7 +288,7 @@ public final class NameRecord extends Record {
|
||||
*/
|
||||
public String getNameText(){
|
||||
|
||||
return this.isBuiltInName() ? this.translateBuiltInName(this.getBuiltInName()) : field_12_name_text;
|
||||
return isBuiltInName() ? translateBuiltInName(getBuiltInName()) : field_12_name_text;
|
||||
}
|
||||
|
||||
/** Gets the Built In Name
|
||||
@ -436,19 +296,19 @@ public final class NameRecord extends Record {
|
||||
*/
|
||||
public byte getBuiltInName()
|
||||
{
|
||||
return this.field_12_builtIn_name;
|
||||
return field_12_built_in_code;
|
||||
}
|
||||
|
||||
|
||||
/** gets the definition, reference (Formula)
|
||||
* @return definition -- can be null if we cant parse ptgs
|
||||
* @return the name formula. never <code>null</code>
|
||||
*/
|
||||
public List getNameDefinition() {
|
||||
return field_13_name_definition;
|
||||
public Ptg[] getNameDefinition() {
|
||||
return (Ptg[]) field_13_name_definition.clone();
|
||||
}
|
||||
|
||||
public void setNameDefinition(Stack nameDefinition) {
|
||||
field_13_name_definition = nameDefinition;
|
||||
public void setNameDefinition(Ptg[] ptgs) {
|
||||
field_13_name_definition = (Ptg[]) ptgs.clone();
|
||||
}
|
||||
|
||||
/** get the custom menu text
|
||||
@ -490,7 +350,8 @@ public final class NameRecord extends Record {
|
||||
throw new RecordFormatException("NOT A valid Name RECORD");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* called by the class that is responsible for writing this sucker.
|
||||
* Subclasses should implement this so that their data is passed back in a
|
||||
@ -498,109 +359,107 @@ public final class NameRecord extends Record {
|
||||
* @param data byte array containing instance data
|
||||
* @return number of bytes written
|
||||
*/
|
||||
public int serialize( int offset, byte[] data )
|
||||
{
|
||||
LittleEndian.putShort( data, 0 + offset, sid );
|
||||
short size = (short)( 15 + getTextsLength() + getNameDefinitionSize());
|
||||
LittleEndian.putShort( data, 2 + offset, size );
|
||||
// size defined below
|
||||
LittleEndian.putShort( data, 4 + offset, getOptionFlag() );
|
||||
data[6 + offset] = getKeyboardShortcut();
|
||||
data[7 + offset] = getNameTextLength();
|
||||
LittleEndian.putShort( data, 8 + offset, getDefinitionLength() );
|
||||
LittleEndian.putShort( data, 10 + offset, getUnused() );
|
||||
LittleEndian.putUShort( data, 12 + offset, field_6_sheetNumber);
|
||||
data[14 + offset] = getCustomMenuLength();
|
||||
data[15 + offset] = getDescriptionTextLength();
|
||||
data[16 + offset] = getHelpTopicLength();
|
||||
data[17 + offset] = getStatusBarLength();
|
||||
data[18 + offset] = getCompressedUnicodeFlag();
|
||||
public int serialize( int offset, byte[] data ) {
|
||||
|
||||
int start_of_name_definition = 19 + field_3_length_name_text;
|
||||
|
||||
if (this.isBuiltInName()) {
|
||||
//can send the builtin name directly in
|
||||
data [19 + offset] = this.getBuiltInName();
|
||||
} else if ((this.getCompressedUnicodeFlag() & 0x01) == 1) {
|
||||
StringUtil.putUnicodeLE( getNameText(), data, 19 + offset );
|
||||
start_of_name_definition = 19 + (2 * field_3_length_name_text);
|
||||
} else {
|
||||
StringUtil.putCompressedUnicode( getNameText(), data, 19 + offset );
|
||||
}
|
||||
|
||||
|
||||
Ptg.serializePtgStack(field_13_name_definition, data, start_of_name_definition + offset );
|
||||
|
||||
|
||||
int start_of_custom_menu_text = start_of_name_definition + field_4_length_name_definition;
|
||||
StringUtil.putCompressedUnicode( getCustomMenuText(), data, start_of_custom_menu_text + offset );
|
||||
|
||||
int start_of_description_text = start_of_custom_menu_text + field_7_length_custom_menu;
|
||||
StringUtil.putCompressedUnicode( getDescriptionText(), data, start_of_description_text + offset );
|
||||
|
||||
int start_of_help_topic_text = start_of_description_text + field_8_length_description_text;
|
||||
StringUtil.putCompressedUnicode( getHelpTopicText(), data, start_of_help_topic_text + offset );
|
||||
|
||||
int start_of_status_bar_text = start_of_help_topic_text + field_9_length_help_topic_text;
|
||||
StringUtil.putCompressedUnicode( getStatusBarText(), data, start_of_status_bar_text + offset );
|
||||
|
||||
return getRecordSize();
|
||||
/* } */
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the length of all texts, in bytes
|
||||
* @return total length
|
||||
*/
|
||||
public int getTextsLength(){
|
||||
int result;
|
||||
|
||||
result = getRawNameTextLength() + getDescriptionTextLength() +
|
||||
getHelpTopicLength() + getStatusBarLength();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private int getNameDefinitionSize() {
|
||||
int result = 0;
|
||||
List list = field_13_name_definition;
|
||||
int field_7_length_custom_menu = field_14_custom_menu_text.length();
|
||||
int field_8_length_description_text = field_15_description_text.length();
|
||||
int field_9_length_help_topic_text = field_16_help_topic_text.length();
|
||||
int field_10_length_status_bar_text = field_17_status_bar_text.length();
|
||||
int rawNameSize = getNameRawSize();
|
||||
|
||||
for (int k = 0; k < list.size(); k++)
|
||||
{
|
||||
Ptg ptg = ( Ptg ) list.get(k);
|
||||
|
||||
result += ptg.getSize();
|
||||
int formulaTotalSize = Ptg.getEncodedSize(field_13_name_definition);
|
||||
int dataSize = 15 // 4 shorts + 7 bytes
|
||||
+ rawNameSize
|
||||
+ field_7_length_custom_menu
|
||||
+ field_8_length_description_text
|
||||
+ field_9_length_help_topic_text
|
||||
+ field_10_length_status_bar_text
|
||||
+ formulaTotalSize;
|
||||
|
||||
LittleEndian.putShort(data, 0 + offset, sid);
|
||||
LittleEndian.putUShort(data, 2 + offset, dataSize);
|
||||
// size defined below
|
||||
LittleEndian.putShort(data, 4 + offset, getOptionFlag());
|
||||
LittleEndian.putByte(data, 6 + offset, getKeyboardShortcut());
|
||||
LittleEndian.putByte(data, 7 + offset, getNameTextLength());
|
||||
// Note -
|
||||
LittleEndian.putUShort(data, 8 + offset, Ptg.getEncodedSizeWithoutArrayData(field_13_name_definition));
|
||||
LittleEndian.putUShort(data, 10 + offset, field_5_index_to_sheet);
|
||||
LittleEndian.putUShort(data, 12 + offset, field_6_sheetNumber);
|
||||
LittleEndian.putByte(data, 14 + offset, field_7_length_custom_menu);
|
||||
LittleEndian.putByte(data, 15 + offset, field_8_length_description_text);
|
||||
LittleEndian.putByte(data, 16 + offset, field_9_length_help_topic_text);
|
||||
LittleEndian.putByte(data, 17 + offset, field_10_length_status_bar_text);
|
||||
LittleEndian.putByte(data, 18 + offset, field_11_nameIsMultibyte ? 1 : 0);
|
||||
int pos = 19 + offset;
|
||||
|
||||
if (isBuiltInName()) {
|
||||
//can send the builtin name directly in
|
||||
LittleEndian.putByte(data, pos, field_12_built_in_code);
|
||||
} else {
|
||||
String nameText = field_12_name_text;
|
||||
if (field_11_nameIsMultibyte) {
|
||||
StringUtil.putUnicodeLE(nameText, data, pos);
|
||||
} else {
|
||||
StringUtil.putCompressedUnicode(nameText, data, pos);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
pos += rawNameSize;
|
||||
|
||||
Ptg.serializePtgs(field_13_name_definition, data, pos);
|
||||
pos += formulaTotalSize;
|
||||
|
||||
StringUtil.putCompressedUnicode( getCustomMenuText(), data, pos);
|
||||
pos += field_7_length_custom_menu;
|
||||
StringUtil.putCompressedUnicode( getDescriptionText(), data, pos);
|
||||
pos += field_8_length_description_text;
|
||||
StringUtil.putCompressedUnicode( getHelpTopicText(), data, pos);
|
||||
pos += field_9_length_help_topic_text;
|
||||
StringUtil.putCompressedUnicode( getStatusBarText(), data, pos);
|
||||
|
||||
return 4 + dataSize;
|
||||
}
|
||||
private int getNameRawSize() {
|
||||
if (isBuiltInName()) {
|
||||
return 1;
|
||||
}
|
||||
int nChars = field_12_name_text.length();
|
||||
if(field_11_nameIsMultibyte) {
|
||||
return 2 * nChars;
|
||||
}
|
||||
return nChars;
|
||||
}
|
||||
|
||||
/** returns the record size
|
||||
*/
|
||||
public int getRecordSize(){
|
||||
int result;
|
||||
|
||||
result = 19 + getTextsLength() + getNameDefinitionSize();
|
||||
|
||||
|
||||
return result;
|
||||
return 4 // sid + size
|
||||
+ 15 // 4 shorts + 7 bytes
|
||||
+ getNameRawSize()
|
||||
+ field_14_custom_menu_text.length()
|
||||
+ field_15_description_text.length()
|
||||
+ field_16_help_topic_text.length()
|
||||
+ field_17_status_bar_text.length()
|
||||
+ Ptg.getEncodedSize(field_13_name_definition);
|
||||
}
|
||||
|
||||
/** gets the extern sheet number
|
||||
* @return extern sheet index
|
||||
*/
|
||||
public short getExternSheetNumber(){
|
||||
if (field_13_name_definition == null || field_13_name_definition.isEmpty()) return 0;
|
||||
Ptg ptg = (Ptg) field_13_name_definition.peek();
|
||||
short result = 0;
|
||||
if (field_13_name_definition.length < 1) {
|
||||
return 0;
|
||||
}
|
||||
Ptg ptg = field_13_name_definition[0];
|
||||
|
||||
if (ptg.getClass() == Area3DPtg.class){
|
||||
result = ((Area3DPtg) ptg).getExternSheetIndex();
|
||||
return ((Area3DPtg) ptg).getExternSheetIndex();
|
||||
|
||||
} else if (ptg.getClass() == Ref3DPtg.class){
|
||||
result = ((Ref3DPtg) ptg).getExternSheetIndex();
|
||||
}
|
||||
|
||||
return result;
|
||||
if (ptg.getClass() == Ref3DPtg.class){
|
||||
return ((Ref3DPtg) ptg).getExternSheetIndex();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** sets the extern sheet number
|
||||
@ -609,11 +468,13 @@ public final class NameRecord extends Record {
|
||||
public void setExternSheetNumber(short externSheetNumber){
|
||||
Ptg ptg;
|
||||
|
||||
if (field_13_name_definition == null || field_13_name_definition.isEmpty()){
|
||||
field_13_name_definition = new Stack();
|
||||
if (field_13_name_definition.length < 1){
|
||||
ptg = createNewPtg();
|
||||
field_13_name_definition = new Ptg[] {
|
||||
ptg,
|
||||
};
|
||||
} else {
|
||||
ptg = (Ptg) field_13_name_definition.peek();
|
||||
ptg = field_13_name_definition[0];
|
||||
}
|
||||
|
||||
if (ptg.getClass() == Area3DPtg.class){
|
||||
@ -625,11 +486,8 @@ public final class NameRecord extends Record {
|
||||
|
||||
}
|
||||
|
||||
private Ptg createNewPtg(){
|
||||
Ptg ptg = new Area3DPtg("A1", 0); // TODO - change to not be partially initialised
|
||||
field_13_name_definition.push(ptg);
|
||||
|
||||
return ptg;
|
||||
private static Ptg createNewPtg(){
|
||||
return new Area3DPtg("A1:A1", 0); // TODO - change to not be partially initialised
|
||||
}
|
||||
|
||||
/** gets the reference , the area only (range)
|
||||
@ -646,16 +504,14 @@ public final class NameRecord extends Record {
|
||||
//Trying to find if what ptg do we need
|
||||
RangeAddress ra = new RangeAddress(ref);
|
||||
Ptg oldPtg;
|
||||
Ptg ptg;
|
||||
|
||||
if (field_13_name_definition==null ||field_13_name_definition.isEmpty()){
|
||||
field_13_name_definition = new Stack();
|
||||
if (field_13_name_definition.length < 1){
|
||||
oldPtg = createNewPtg();
|
||||
} else {
|
||||
//Trying to find extern sheet index
|
||||
oldPtg = (Ptg) field_13_name_definition.pop();
|
||||
oldPtg = field_13_name_definition[0];
|
||||
}
|
||||
|
||||
List temp = new ArrayList();
|
||||
short externSheetIndex = 0;
|
||||
|
||||
if (oldPtg.getClass() == Area3DPtg.class){
|
||||
@ -667,29 +523,27 @@ public final class NameRecord extends Record {
|
||||
|
||||
if (ra.hasRange()) {
|
||||
// Is it contiguous or not?
|
||||
AreaReference[] refs =
|
||||
AreaReference.generateContiguous(ref);
|
||||
this.setDefinitionTextLength((short)0);
|
||||
AreaReference[] refs = AreaReference.generateContiguous(ref);
|
||||
|
||||
// Add the area reference(s)
|
||||
// Add the area reference(s)
|
||||
for(int i=0; i<refs.length; i++) {
|
||||
ptg = new Area3DPtg(refs[i].formatAsString(), externSheetIndex);
|
||||
field_13_name_definition.push(ptg);
|
||||
this.setDefinitionTextLength( (short)(getDefinitionLength() + ptg.getSize()) );
|
||||
Ptg ptg = new Area3DPtg(refs[i].formatAsString(), externSheetIndex);
|
||||
temp.add(ptg);
|
||||
}
|
||||
// And then a union if we had more than one area
|
||||
if(refs.length > 1) {
|
||||
ptg = UnionPtg.instance;
|
||||
field_13_name_definition.push(ptg);
|
||||
this.setDefinitionTextLength( (short)(getDefinitionLength() + ptg.getSize()) );
|
||||
Ptg ptg = UnionPtg.instance;
|
||||
temp.add(ptg);
|
||||
}
|
||||
} else {
|
||||
ptg = new Ref3DPtg();
|
||||
Ptg ptg = new Ref3DPtg();
|
||||
((Ref3DPtg) ptg).setExternSheetIndex(externSheetIndex);
|
||||
((Ref3DPtg) ptg).setArea(ref);
|
||||
field_13_name_definition.push(ptg);
|
||||
this.setDefinitionTextLength((short)ptg.getSize());
|
||||
temp.add(ptg);
|
||||
}
|
||||
Ptg[] ptgs = new Ptg[temp.size()];
|
||||
temp.toArray(ptgs);
|
||||
field_13_name_definition = ptgs;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -699,40 +553,36 @@ public final class NameRecord extends Record {
|
||||
* @param in the RecordInputstream to read the record from
|
||||
*/
|
||||
protected void fillFields(RecordInputStream in) {
|
||||
field_1_option_flag = in.readShort();
|
||||
field_2_keyboard_shortcut = in.readByte();
|
||||
field_3_length_name_text = in.readByte();
|
||||
field_4_length_name_definition = in.readShort();
|
||||
field_5_index_to_sheet = in.readShort();
|
||||
field_6_sheetNumber = in.readUShort();
|
||||
field_7_length_custom_menu = in.readByte();
|
||||
field_8_length_description_text = in.readByte();
|
||||
field_9_length_help_topic_text = in.readByte();
|
||||
field_10_length_status_bar_text = in.readByte();
|
||||
|
||||
//store the name in byte form if it's a builtin name
|
||||
field_11_compressed_unicode_flag= in.readByte();
|
||||
if (this.isBuiltInName()) {
|
||||
field_12_builtIn_name = in.readByte();
|
||||
} else {
|
||||
if (field_11_compressed_unicode_flag == 1) {
|
||||
field_12_name_text = in.readUnicodeLEString(field_3_length_name_text);
|
||||
} else {
|
||||
field_12_name_text = in.readCompressedUnicode(field_3_length_name_text);
|
||||
}
|
||||
field_1_option_flag = in.readShort();
|
||||
field_2_keyboard_shortcut = in.readByte();
|
||||
int field_3_length_name_text = in.readByte();
|
||||
int field_4_length_name_definition = in.readShort();
|
||||
field_5_index_to_sheet = in.readShort();
|
||||
field_6_sheetNumber = in.readUShort();
|
||||
int field_7_length_custom_menu = in.readUByte();
|
||||
int field_8_length_description_text = in.readUByte();
|
||||
int field_9_length_help_topic_text = in.readUByte();
|
||||
int field_10_length_status_bar_text = in.readUByte();
|
||||
|
||||
//store the name in byte form if it's a built-in name
|
||||
field_11_nameIsMultibyte = (in.readByte() != 0);
|
||||
if (isBuiltInName()) {
|
||||
field_12_built_in_code = in.readByte();
|
||||
} else {
|
||||
if (field_11_nameIsMultibyte) {
|
||||
field_12_name_text = in.readUnicodeLEString(field_3_length_name_text);
|
||||
} else {
|
||||
field_12_name_text = in.readCompressedUnicode(field_3_length_name_text);
|
||||
}
|
||||
}
|
||||
|
||||
field_13_name_definition = Ptg.createParsedExpressionTokens(field_4_length_name_definition, in);
|
||||
|
||||
|
||||
field_13_name_definition = Ptg.readTokens(field_4_length_name_definition, in);
|
||||
|
||||
//Who says that this can only ever be compressed unicode???
|
||||
field_14_custom_menu_text = in.readCompressedUnicode(LittleEndian.ubyteToInt(field_7_length_custom_menu));
|
||||
|
||||
field_15_description_text = in.readCompressedUnicode(LittleEndian.ubyteToInt(field_8_length_description_text));
|
||||
|
||||
field_16_help_topic_text = in.readCompressedUnicode(LittleEndian.ubyteToInt(field_9_length_help_topic_text));
|
||||
|
||||
field_17_status_bar_text = in.readCompressedUnicode(LittleEndian.ubyteToInt(field_10_length_status_bar_text));
|
||||
/*} */
|
||||
field_14_custom_menu_text = in.readCompressedUnicode(field_7_length_custom_menu);
|
||||
field_15_description_text = in.readCompressedUnicode(field_8_length_description_text);
|
||||
field_16_help_topic_text = in.readCompressedUnicode(field_9_length_help_topic_text);
|
||||
field_17_status_bar_text = in.readCompressedUnicode(field_10_length_status_bar_text);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -742,113 +592,90 @@ public final class NameRecord extends Record {
|
||||
return sid;
|
||||
}
|
||||
/*
|
||||
20 00
|
||||
00
|
||||
01
|
||||
20 00
|
||||
00
|
||||
01
|
||||
1A 00 // sz = 0x1A = 26
|
||||
00 00
|
||||
01 00
|
||||
00
|
||||
00
|
||||
00
|
||||
00
|
||||
00 00
|
||||
01 00
|
||||
00
|
||||
00
|
||||
00
|
||||
00
|
||||
00 // unicode flag
|
||||
07 // name
|
||||
|
||||
|
||||
29 17 00 3B 00 00 00 00 FF FF 00 00 02 00 3B 00 //{ 26
|
||||
00 07 00 07 00 00 00 FF 00 10 // }
|
||||
|
||||
|
||||
|
||||
20 00
|
||||
00
|
||||
01
|
||||
|
||||
|
||||
|
||||
20 00
|
||||
00
|
||||
01
|
||||
0B 00 // sz = 0xB = 11
|
||||
00 00
|
||||
01 00
|
||||
00
|
||||
00
|
||||
00
|
||||
00
|
||||
00 00
|
||||
01 00
|
||||
00
|
||||
00
|
||||
00
|
||||
00
|
||||
00 // unicode flag
|
||||
07 // name
|
||||
|
||||
|
||||
3B 00 00 07 00 07 00 00 00 FF 00 // { 11 }
|
||||
*/
|
||||
/*
|
||||
18, 00,
|
||||
1B, 00,
|
||||
|
||||
20, 00,
|
||||
00,
|
||||
01,
|
||||
0B, 00,
|
||||
00,
|
||||
00,
|
||||
00,
|
||||
00,
|
||||
00,
|
||||
07,
|
||||
3B 00 00 07 00 07 00 00 00 FF 00 ]
|
||||
18, 00,
|
||||
1B, 00,
|
||||
|
||||
20, 00,
|
||||
00,
|
||||
01,
|
||||
0B, 00,
|
||||
00,
|
||||
00,
|
||||
00,
|
||||
00,
|
||||
00,
|
||||
07,
|
||||
3B 00 00 07 00 07 00 00 00 FF 00 ]
|
||||
*/
|
||||
|
||||
/**
|
||||
* @see Object#toString()
|
||||
*/
|
||||
public String toString() {
|
||||
StringBuffer buffer = new StringBuffer();
|
||||
StringBuffer sb = new StringBuffer();
|
||||
|
||||
buffer.append("[NAME]\n");
|
||||
buffer.append(" .option flags = ").append( HexDump.toHex( field_1_option_flag ) )
|
||||
.append("\n");
|
||||
buffer.append(" .keyboard shortcut = ").append( HexDump.toHex( field_2_keyboard_shortcut ) )
|
||||
.append("\n");
|
||||
buffer.append(" .length of the name = ").append( field_3_length_name_text )
|
||||
.append("\n");
|
||||
buffer.append(" .size of the formula data = ").append( field_4_length_name_definition )
|
||||
.append("\n");
|
||||
buffer.append(" .unused = ").append( field_5_index_to_sheet )
|
||||
.append("\n");
|
||||
buffer.append(" .index to sheet (1-based, 0=Global) = ").append( field_6_sheetNumber )
|
||||
.append("\n");
|
||||
buffer.append(" .Length of menu text (character count) = ").append( field_7_length_custom_menu )
|
||||
.append("\n");
|
||||
buffer.append(" .Length of description text (character count) = ").append( field_8_length_description_text )
|
||||
.append("\n");
|
||||
buffer.append(" .Length of help topic text (character count) = ").append( field_9_length_help_topic_text )
|
||||
.append("\n");
|
||||
buffer.append(" .Length of status bar text (character count) = ").append( field_10_length_status_bar_text )
|
||||
.append("\n");
|
||||
buffer.append(" .Name (Unicode flag) = ").append( field_11_compressed_unicode_flag )
|
||||
.append("\n");
|
||||
buffer.append(" .Name (Unicode text) = ").append( getNameText() )
|
||||
.append("\n");
|
||||
|
||||
buffer.append(" .Parts (" + field_13_name_definition.size() +"):")
|
||||
.append("\n");
|
||||
Iterator it = field_13_name_definition.iterator();
|
||||
while(it.hasNext()) {
|
||||
Ptg ptg = (Ptg)it.next();
|
||||
buffer.append(" " + ptg.toString()).append("\n");
|
||||
sb.append("[NAME]\n");
|
||||
sb.append(" .option flags = ").append(HexDump.shortToHex(field_1_option_flag)).append("\n");
|
||||
sb.append(" .keyboard shortcut = ").append(HexDump.byteToHex(field_2_keyboard_shortcut)).append("\n");
|
||||
sb.append(" .length of the name = ").append(getNameTextLength()).append("\n");
|
||||
sb.append(" .unused = ").append( field_5_index_to_sheet ).append("\n");
|
||||
sb.append(" .index to sheet (1-based, 0=Global) = ").append( field_6_sheetNumber ).append("\n");
|
||||
sb.append(" .Menu text length = ").append(field_14_custom_menu_text.length()).append("\n");
|
||||
sb.append(" .Description text length= ").append(field_15_description_text.length()).append("\n");
|
||||
sb.append(" .Help topic text length = ").append(field_16_help_topic_text.length()).append("\n");
|
||||
sb.append(" .Status bar text length = ").append(field_17_status_bar_text.length()).append("\n");
|
||||
sb.append(" .NameIsMultibyte = ").append(field_11_nameIsMultibyte).append("\n");
|
||||
sb.append(" .Name (Unicode text) = ").append( getNameText() ).append("\n");
|
||||
sb.append(" .Formula (nTokens=").append(field_13_name_definition.length).append("):") .append("\n");
|
||||
for (int i = 0; i < field_13_name_definition.length; i++) {
|
||||
Ptg ptg = field_13_name_definition[i];
|
||||
sb.append(" " + ptg.toString()).append(ptg.getRVAType()).append("\n");
|
||||
}
|
||||
|
||||
buffer.append(" .Menu text (Unicode string without length field) = ").append( field_14_custom_menu_text )
|
||||
.append("\n");
|
||||
buffer.append(" .Description text (Unicode string without length field) = ").append( field_15_description_text )
|
||||
.append("\n");
|
||||
buffer.append(" .Help topic text (Unicode string without length field) = ").append( field_16_help_topic_text )
|
||||
.append("\n");
|
||||
buffer.append(" .Status bar text (Unicode string without length field) = ").append( field_17_status_bar_text )
|
||||
.append("\n");
|
||||
buffer.append("[/NAME]\n");
|
||||
|
||||
return buffer.toString();
|
||||
|
||||
sb.append(" .Menu text = ").append(field_14_custom_menu_text).append("\n");
|
||||
sb.append(" .Description text= ").append(field_15_description_text).append("\n");
|
||||
sb.append(" .Help topic text = ").append(field_16_help_topic_text).append("\n");
|
||||
sb.append(" .Status bar text = ").append(field_17_status_bar_text).append("\n");
|
||||
sb.append("[/NAME]\n");
|
||||
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
/**Creates a human readable name for built in types
|
||||
* @return Unknown if the built-in name cannot be translated
|
||||
*/
|
||||
protected String translateBuiltInName(byte name)
|
||||
private static String translateBuiltInName(byte name)
|
||||
{
|
||||
switch (name)
|
||||
{
|
||||
@ -859,14 +686,15 @@ public final class NameRecord extends Record {
|
||||
case NameRecord.BUILTIN_CONSOLIDATE_AREA : return "Consolidate_Area";
|
||||
case NameRecord.BUILTIN_CRITERIA : return "Criteria";
|
||||
case NameRecord.BUILTIN_DATABASE : return "Database";
|
||||
case NameRecord.BUILTIN_DATA_FORM : return "Data_Form";
|
||||
case NameRecord.BUILTIN_DATA_FORM : return "Data_Form";
|
||||
case NameRecord.BUILTIN_PRINT_AREA : return "Print_Area";
|
||||
case NameRecord.BUILTIN_PRINT_TITLE : return "Print_Titles";
|
||||
case NameRecord.BUILTIN_RECORDER : return "Recorder";
|
||||
case NameRecord.BUILTIN_SHEET_TITLE : return "Sheet_Title";
|
||||
|
||||
case NameRecord.BUILTIN_FILTER_DB : return "_FilterDatabase";
|
||||
|
||||
}
|
||||
|
||||
|
||||
return "Unknown";
|
||||
}
|
||||
}
|
||||
|
@ -94,10 +94,14 @@ public final class ArrayPtg extends Ptg {
|
||||
|
||||
buffer.append("columns = ").append(getColumnCount()).append("\n");
|
||||
buffer.append("rows = ").append(getRowCount()).append("\n");
|
||||
for (int x=0;x<getColumnCount();x++) {
|
||||
for (int y=0;y<getRowCount();y++) {
|
||||
Object o = token_3_arrayValues[getValueIndex(x, y)];
|
||||
buffer.append("[").append(x).append("][").append(y).append("] = ").append(o).append("\n");
|
||||
if (token_3_arrayValues == null) {
|
||||
buffer.append(" #values#uninitialised#\n");
|
||||
} else {
|
||||
for (int x=0;x<getColumnCount();x++) {
|
||||
for (int y=0;y<getRowCount();y++) {
|
||||
Object o = token_3_arrayValues[getValueIndex(x, y)];
|
||||
buffer.append("[").append(x).append("][").append(y).append("] = ").append(o).append("\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
return buffer.toString();
|
||||
|
@ -41,7 +41,7 @@ public final class Ref3DPtg extends OperandPtg {
|
||||
private static final BitField colRelative = BitFieldFactory.getInstance(0x4000);
|
||||
|
||||
private final static int SIZE = 7; // 6 + 1 for Ptg
|
||||
private short field_1_index_extern_sheet;
|
||||
private int field_1_index_extern_sheet;
|
||||
/** The row index - zero based unsigned 16 bit value */
|
||||
private int field_2_row;
|
||||
/** Field 2
|
||||
@ -93,10 +93,10 @@ public final class Ref3DPtg extends OperandPtg {
|
||||
}
|
||||
|
||||
public short getExternSheetIndex(){
|
||||
return field_1_index_extern_sheet;
|
||||
return (short)field_1_index_extern_sheet;
|
||||
}
|
||||
|
||||
public void setExternSheetIndex(short index){
|
||||
public void setExternSheetIndex(int index){
|
||||
field_1_index_extern_sheet = index;
|
||||
}
|
||||
|
||||
|
@ -109,8 +109,8 @@ public final class AnalysisToolPak {
|
||||
r(m, "IMSUB", null);
|
||||
r(m, "IMSUM", null);
|
||||
r(m, "INTRATE", null);
|
||||
r(m, "ISEVEN", null);
|
||||
r(m, "ISODD", null);
|
||||
r(m, "ISEVEN", ParityFunction.IS_EVEN);
|
||||
r(m, "ISODD", ParityFunction.IS_ODD);
|
||||
r(m, "LCM", null);
|
||||
r(m, "MDURATION", null);
|
||||
r(m, "MROUND", null);
|
||||
|
@ -0,0 +1,74 @@
|
||||
/* ====================================================================
|
||||
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.atp;
|
||||
|
||||
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.EvaluationException;
|
||||
import org.apache.poi.hssf.record.formula.eval.OperandResolver;
|
||||
import org.apache.poi.hssf.record.formula.eval.ValueEval;
|
||||
import org.apache.poi.hssf.record.formula.functions.FreeRefFunction;
|
||||
import org.apache.poi.ss.usermodel.Sheet;
|
||||
import org.apache.poi.ss.usermodel.Workbook;
|
||||
/**
|
||||
* Implementation of Excel 'Analysis ToolPak' function ISEVEN() ISODD()<br/>
|
||||
*
|
||||
* @author Josh Micich
|
||||
*/
|
||||
final class ParityFunction implements FreeRefFunction {
|
||||
|
||||
public static final FreeRefFunction IS_EVEN = new ParityFunction(0);
|
||||
public static final FreeRefFunction IS_ODD = new ParityFunction(1);
|
||||
private final int _desiredParity;
|
||||
|
||||
private ParityFunction(int desiredParity) {
|
||||
_desiredParity = desiredParity;
|
||||
}
|
||||
|
||||
public ValueEval evaluate(Eval[] args, int srcCellRow, short srcCellCol, Workbook workbook,
|
||||
Sheet sheet) {
|
||||
if (args.length != 1) {
|
||||
return ErrorEval.VALUE_INVALID;
|
||||
}
|
||||
|
||||
int val;
|
||||
try {
|
||||
val = evaluateArgParity(args[0], srcCellRow, srcCellCol);
|
||||
} catch (EvaluationException e) {
|
||||
return e.getErrorEval();
|
||||
}
|
||||
|
||||
return BoolEval.valueOf(val == _desiredParity);
|
||||
}
|
||||
|
||||
private static int evaluateArgParity(Eval arg, int srcCellRow, short srcCellCol) throws EvaluationException {
|
||||
ValueEval ve = OperandResolver.getSingleValue(arg, srcCellRow, srcCellCol);
|
||||
|
||||
if (ve == BlankEval.INSTANCE) {
|
||||
return 0;
|
||||
}
|
||||
double d = OperandResolver.coerceValueToDouble(ve);
|
||||
if (d < 0) {
|
||||
d = -d;
|
||||
}
|
||||
long v = (long) Math.floor(d);
|
||||
return (int) (v & 0x0001);
|
||||
}
|
||||
}
|
@ -21,6 +21,7 @@ import java.util.Calendar;
|
||||
import java.util.GregorianCalendar;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import org.apache.poi.hssf.record.formula.eval.BlankEval;
|
||||
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;
|
||||
@ -96,6 +97,9 @@ final class YearFrac implements FreeRefFunction {
|
||||
Calendar date = parseDate(strVal);
|
||||
return DateUtil.getExcelDate(date, false);
|
||||
}
|
||||
if (ve instanceof BlankEval) {
|
||||
return 0.0;
|
||||
}
|
||||
return OperandResolver.coerceValueToDouble(ve);
|
||||
}
|
||||
|
||||
@ -120,7 +124,7 @@ final class YearFrac implements FreeRefFunction {
|
||||
} catch (NumberFormatException e) {
|
||||
throw new EvaluationException(ErrorEval.VALUE_INVALID);
|
||||
}
|
||||
if (f0<0 || f1<0 || f2<0 || f0>12 || f1>12 || f2>12) {
|
||||
if (f0<0 || f1<0 || f2<0 || (f0>12 && f1>12 && f2>12)) {
|
||||
// easy to see this cannot be a valid date
|
||||
throw new EvaluationException(ErrorEval.VALUE_INVALID);
|
||||
}
|
||||
@ -150,6 +154,7 @@ final class YearFrac implements FreeRefFunction {
|
||||
if (day <1 || day>cal.getActualMaximum(Calendar.DAY_OF_MONTH)) {
|
||||
throw new EvaluationException(ErrorEval.VALUE_INVALID);
|
||||
}
|
||||
cal.set(Calendar.DAY_OF_MONTH, day);
|
||||
return cal;
|
||||
}
|
||||
|
||||
|
@ -1,27 +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.
|
||||
*/
|
||||
/*
|
||||
* Created on May 8, 2005
|
||||
*
|
||||
*/
|
||||
/* ====================================================================
|
||||
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.AddPtg;
|
||||
import org.apache.poi.hssf.record.formula.Ptg;
|
||||
|
||||
/**
|
||||
* @author Amol S. Deshmukh < amolweb at ya hoo dot com >
|
||||
@ -37,58 +32,14 @@ import org.apache.poi.hssf.record.formula.Ptg;
|
||||
* <li> 1+A1 = 2 if A1 contains TRUE or =TRUE
|
||||
* <li> 1+A1 = #VALUE! if A1 contains "TRUE" or ="TRUE"
|
||||
*/
|
||||
public class AddEval extends NumericOperationEval {
|
||||
public final class AddEval extends TwoOperandNumericOperation {
|
||||
|
||||
private AddPtg delegate;
|
||||
private static final ValueEvalToNumericXlator NUM_XLATOR =
|
||||
new ValueEvalToNumericXlator((short)
|
||||
( ValueEvalToNumericXlator.BOOL_IS_PARSED
|
||||
| ValueEvalToNumericXlator.REF_BOOL_IS_PARSED
|
||||
| ValueEvalToNumericXlator.STRING_IS_PARSED
|
||||
| ValueEvalToNumericXlator.REF_STRING_IS_PARSED
|
||||
));
|
||||
public static final OperationEval instance = new AddEval();
|
||||
|
||||
public AddEval(Ptg ptg) {
|
||||
delegate = (AddPtg) ptg;
|
||||
}
|
||||
private AddEval() {
|
||||
}
|
||||
|
||||
public ValueEvalToNumericXlator getXlator() {
|
||||
return NUM_XLATOR;
|
||||
}
|
||||
|
||||
|
||||
public Eval evaluate(Eval[] args, int srcRow, short srcCol) {
|
||||
if(args.length != 2) {
|
||||
return ErrorEval.VALUE_INVALID;
|
||||
}
|
||||
|
||||
double d = 0;
|
||||
for (int i = 0; i < 2; i++) {
|
||||
ValueEval ve = singleOperandEvaluate(args[i], srcRow, srcCol);
|
||||
if(ve instanceof ErrorEval) {
|
||||
return ve;
|
||||
}
|
||||
if (ve instanceof NumericValueEval) {
|
||||
d += ((NumericValueEval) ve).getNumberValue();
|
||||
}
|
||||
else if (ve instanceof BlankEval) {
|
||||
// do nothing
|
||||
}
|
||||
else {
|
||||
return ErrorEval.VALUE_INVALID;
|
||||
}
|
||||
}
|
||||
if(Double.isNaN(d) || Double.isInfinite(d)) {
|
||||
return ErrorEval.NUM_ERROR;
|
||||
}
|
||||
return new NumberEval(d);
|
||||
}
|
||||
|
||||
public int getNumberOfOperands() {
|
||||
return delegate.getNumberOfOperands();
|
||||
}
|
||||
|
||||
public int getType() {
|
||||
return delegate.getType();
|
||||
}
|
||||
protected double evaluate(double d0, double d1) {
|
||||
return d0 + d1;
|
||||
}
|
||||
}
|
||||
|
@ -1,95 +1,36 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
import org.apache.poi.hssf.record.formula.Ptg;
|
||||
import org.apache.poi.hssf.record.formula.DividePtg;
|
||||
|
||||
/**
|
||||
* @author Amol S. Deshmukh < amolweb at ya hoo dot com >
|
||||
*
|
||||
*/
|
||||
public final class DivideEval extends NumericOperationEval {
|
||||
public final class DivideEval extends TwoOperandNumericOperation {
|
||||
|
||||
private DividePtg delegate;
|
||||
public static final OperationEval instance = new DivideEval();
|
||||
|
||||
private static final ValueEvalToNumericXlator NUM_XLATOR =
|
||||
new ValueEvalToNumericXlator((short)
|
||||
( ValueEvalToNumericXlator.BOOL_IS_PARSED
|
||||
| ValueEvalToNumericXlator.REF_BOOL_IS_PARSED
|
||||
| ValueEvalToNumericXlator.STRING_IS_PARSED
|
||||
| ValueEvalToNumericXlator.REF_STRING_IS_PARSED
|
||||
));
|
||||
private DivideEval() {
|
||||
}
|
||||
|
||||
public DivideEval(Ptg ptg) {
|
||||
delegate = (DividePtg) ptg;
|
||||
}
|
||||
|
||||
protected ValueEvalToNumericXlator getXlator() {
|
||||
return NUM_XLATOR;
|
||||
}
|
||||
|
||||
public Eval evaluate(Eval[] args, int srcRow, short srcCol) {
|
||||
if(args.length != 2) {
|
||||
return ErrorEval.VALUE_INVALID;
|
||||
}
|
||||
Eval retval = null;
|
||||
double d0 = 0;
|
||||
double d1 = 0;
|
||||
ValueEval ve = singleOperandEvaluate(args[0], srcRow, srcCol);
|
||||
if (ve instanceof NumericValueEval) {
|
||||
d0 = ((NumericValueEval) ve).getNumberValue();
|
||||
}
|
||||
else if (ve instanceof BlankEval) {
|
||||
// do nothing
|
||||
}
|
||||
else {
|
||||
retval = ErrorEval.VALUE_INVALID;
|
||||
}
|
||||
|
||||
if (retval == null) { // no error yet
|
||||
ve = singleOperandEvaluate(args[1], srcRow, srcCol);
|
||||
if (ve instanceof NumericValueEval) {
|
||||
d1 = ((NumericValueEval) ve).getNumberValue();
|
||||
}
|
||||
else if (ve instanceof BlankEval) {
|
||||
// do nothing
|
||||
}
|
||||
else {
|
||||
retval = ErrorEval.VALUE_INVALID;
|
||||
}
|
||||
}
|
||||
|
||||
if (retval == null) {
|
||||
retval = (d1 == 0)
|
||||
? ErrorEval.DIV_ZERO
|
||||
: (Double.isNaN(d0) || Double.isNaN(d1))
|
||||
? (ValueEval) ErrorEval.VALUE_INVALID
|
||||
: new NumberEval(d0 / d1);
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
|
||||
public int getNumberOfOperands() {
|
||||
return delegate.getNumberOfOperands();
|
||||
}
|
||||
|
||||
public int getType() {
|
||||
return delegate.getType();
|
||||
}
|
||||
protected double evaluate(double d0, double d1) throws EvaluationException {
|
||||
if (d1 == 0.0) {
|
||||
throw new EvaluationException(ErrorEval.DIV_ZERO);
|
||||
}
|
||||
return d0 / d1;
|
||||
}
|
||||
}
|
||||
|
@ -1,67 +1,34 @@
|
||||
/*
|
||||
* 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 May 8, 2005
|
||||
*
|
||||
*/
|
||||
package org.apache.poi.hssf.record.formula.eval;
|
||||
/* ====================================================================
|
||||
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
|
||||
|
||||
import org.apache.poi.hssf.record.formula.EqualPtg;
|
||||
import org.apache.poi.hssf.record.formula.Ptg;
|
||||
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;
|
||||
|
||||
/**
|
||||
* @author Amol S. Deshmukh < amolweb at ya hoo dot com >
|
||||
*
|
||||
*/
|
||||
public class EqualEval extends RelationalOperationEval {
|
||||
public final class EqualEval extends RelationalOperationEval {
|
||||
|
||||
private EqualPtg delegate;
|
||||
public static final OperationEval instance = new EqualEval();
|
||||
|
||||
private EqualEval() {
|
||||
}
|
||||
|
||||
public EqualEval(Ptg ptg) {
|
||||
this.delegate = (EqualPtg) ptg;
|
||||
}
|
||||
|
||||
|
||||
public Eval evaluate(Eval[] operands, int srcRow, short srcCol) {
|
||||
ValueEval retval = null;
|
||||
|
||||
RelationalValues rvs = super.doEvaluate(operands, srcRow, srcCol);
|
||||
retval = rvs.ee;
|
||||
int result = 0;
|
||||
if (retval == null) {
|
||||
result = doComparison(rvs.bs);
|
||||
if (result == 0) {
|
||||
result = doComparison(rvs.ss);
|
||||
}
|
||||
if (result == 0) {
|
||||
result = doComparison(rvs.ds);
|
||||
}
|
||||
|
||||
retval = (result == 0) ? BoolEval.TRUE : BoolEval.FALSE;
|
||||
}
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
public int getNumberOfOperands() {
|
||||
return delegate.getNumberOfOperands();
|
||||
}
|
||||
|
||||
public int getType() {
|
||||
return delegate.getType();
|
||||
}
|
||||
protected boolean convertComparisonResult(int cmpResult) {
|
||||
return cmpResult == 0;
|
||||
}
|
||||
}
|
||||
|
@ -42,7 +42,7 @@ final class ExternalFunction implements FreeRefFunction {
|
||||
FreeRefFunction targetFunc;
|
||||
try {
|
||||
if (nameArg instanceof NameEval) {
|
||||
targetFunc = findInternalUserDefinedFunction(workbook, (NameEval) nameArg);
|
||||
targetFunc = findInternalUserDefinedFunction((NameEval) nameArg);
|
||||
} else if (nameArg instanceof NameXEval) {
|
||||
targetFunc = findExternalUserDefinedFunction(workbook, (NameXEval) nameArg);
|
||||
} else {
|
||||
@ -65,7 +65,7 @@ final class ExternalFunction implements FreeRefFunction {
|
||||
if(false) {
|
||||
System.out.println("received call to external user defined function (" + functionName + ")");
|
||||
}
|
||||
// currently only looking for functions from the 'Analysis TookPak'
|
||||
// currently only looking for functions from the 'Analysis TookPak' e.g. "YEARFRAC" or "ISEVEN"
|
||||
// not sure how much this logic would need to change to support other or multiple add-ins.
|
||||
FreeRefFunction result = AnalysisToolPak.findFunction(functionName);
|
||||
if (result != null) {
|
||||
@ -74,24 +74,12 @@ final class ExternalFunction implements FreeRefFunction {
|
||||
throw new EvaluationException(ErrorEval.FUNCTION_NOT_IMPLEMENTED);
|
||||
}
|
||||
|
||||
private FreeRefFunction findInternalUserDefinedFunction(Workbook workbook, NameEval functionNameEval) throws EvaluationException {
|
||||
|
||||
int numberOfNames = workbook.getNumberOfNames();
|
||||
|
||||
int nameIndex = functionNameEval.getIndex();
|
||||
if(nameIndex < 0 || nameIndex >= numberOfNames) {
|
||||
throw new RuntimeException("Bad name index (" + nameIndex
|
||||
+ "). Allowed range is (0.." + (numberOfNames-1) + ")");
|
||||
}
|
||||
|
||||
String functionName = workbook.getNameName(nameIndex);
|
||||
private FreeRefFunction findInternalUserDefinedFunction(NameEval functionNameEval) throws EvaluationException {
|
||||
String functionName = functionNameEval.getFunctionName();
|
||||
if(false) {
|
||||
System.out.println("received call to internal user defined function (" + functionName + ")");
|
||||
}
|
||||
// TODO - detect if the NameRecord corresponds to a named range, function, or something undefined
|
||||
// throw the right errors in these cases
|
||||
|
||||
// TODO find the implementation for the external function e.g. "YEARFRAC" or "ISEVEN"
|
||||
// TODO find the implementation for the user defined function
|
||||
|
||||
throw new EvaluationException(ErrorEval.FUNCTION_NOT_IMPLEMENTED);
|
||||
}
|
||||
|
@ -1,67 +1,34 @@
|
||||
/*
|
||||
* 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 May 8, 2005
|
||||
*
|
||||
*/
|
||||
package org.apache.poi.hssf.record.formula.eval;
|
||||
/* ====================================================================
|
||||
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
|
||||
|
||||
import org.apache.poi.hssf.record.formula.GreaterEqualPtg;
|
||||
import org.apache.poi.hssf.record.formula.Ptg;
|
||||
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;
|
||||
|
||||
/**
|
||||
* @author Amol S. Deshmukh < amolweb at ya hoo dot com >
|
||||
*
|
||||
*/
|
||||
public class GreaterEqualEval extends RelationalOperationEval {
|
||||
public final class GreaterEqualEval extends RelationalOperationEval {
|
||||
|
||||
private GreaterEqualPtg delegate;
|
||||
|
||||
public GreaterEqualEval(Ptg ptg) {
|
||||
this.delegate = (GreaterEqualPtg) ptg;
|
||||
}
|
||||
|
||||
public Eval evaluate(Eval[] operands, int srcRow, short srcCol) {
|
||||
ValueEval retval = null;
|
||||
|
||||
RelationalValues rvs = super.doEvaluate(operands, srcRow, srcCol);
|
||||
retval = rvs.ee;
|
||||
int result = 0;
|
||||
if (retval == null) {
|
||||
result = doComparison(rvs.bs);
|
||||
if (result == 0) {
|
||||
result = doComparison(rvs.ss);
|
||||
}
|
||||
if (result == 0) {
|
||||
result = doComparison(rvs.ds);
|
||||
}
|
||||
|
||||
retval = (result >= 0) ? BoolEval.TRUE : BoolEval.FALSE;
|
||||
}
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
public int getNumberOfOperands() {
|
||||
return delegate.getNumberOfOperands();
|
||||
}
|
||||
|
||||
public int getType() {
|
||||
return delegate.getType();
|
||||
}
|
||||
public static final OperationEval instance = new GreaterEqualEval();
|
||||
|
||||
private GreaterEqualEval() {
|
||||
}
|
||||
|
||||
protected boolean convertComparisonResult(int cmpResult) {
|
||||
return cmpResult >= 0;
|
||||
}
|
||||
}
|
||||
|
@ -1,67 +1,34 @@
|
||||
/*
|
||||
* 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 May 8, 2005
|
||||
*
|
||||
*/
|
||||
package org.apache.poi.hssf.record.formula.eval;
|
||||
/* ====================================================================
|
||||
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
|
||||
|
||||
import org.apache.poi.hssf.record.formula.GreaterThanPtg;
|
||||
import org.apache.poi.hssf.record.formula.Ptg;
|
||||
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;
|
||||
|
||||
/**
|
||||
* @author Amol S. Deshmukh < amolweb at ya hoo dot com >
|
||||
*
|
||||
*/
|
||||
public class GreaterThanEval extends RelationalOperationEval {
|
||||
public final class GreaterThanEval extends RelationalOperationEval {
|
||||
|
||||
private GreaterThanPtg delegate;
|
||||
|
||||
public GreaterThanEval(Ptg ptg) {
|
||||
this.delegate = (GreaterThanPtg) ptg;
|
||||
}
|
||||
|
||||
public Eval evaluate(Eval[] operands, int srcRow, short srcCol) {
|
||||
ValueEval retval = null;
|
||||
|
||||
RelationalValues rvs = super.doEvaluate(operands, srcRow, srcCol);
|
||||
retval = rvs.ee;
|
||||
int result = 0;
|
||||
if (retval == null) {
|
||||
result = doComparison(rvs.bs);
|
||||
if (result == 0) {
|
||||
result = doComparison(rvs.ss);
|
||||
}
|
||||
if (result == 0) {
|
||||
result = doComparison(rvs.ds);
|
||||
}
|
||||
|
||||
retval = (result > 0) ? BoolEval.TRUE : BoolEval.FALSE;;
|
||||
}
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
public int getNumberOfOperands() {
|
||||
return delegate.getNumberOfOperands();
|
||||
}
|
||||
|
||||
public int getType() {
|
||||
return delegate.getType();
|
||||
}
|
||||
public static final OperationEval instance = new GreaterThanEval();
|
||||
|
||||
private GreaterThanEval() {
|
||||
}
|
||||
|
||||
protected boolean convertComparisonResult(int cmpResult) {
|
||||
return cmpResult > 0;
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
|
||||
@ -24,20 +24,21 @@ 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;
|
||||
import org.apache.poi.ss.util.CellReference;
|
||||
|
||||
/**
|
||||
* @author Amol S. Deshmukh < amolweb at ya hoo dot com >
|
||||
*
|
||||
*
|
||||
* @author Josh Micich
|
||||
*/
|
||||
public final class LazyAreaEval extends AreaEvalBase {
|
||||
|
||||
private final Sheet _sheet;
|
||||
private Workbook _workbook;
|
||||
private FormulaEvaluator _evaluator;
|
||||
|
||||
public LazyAreaEval(AreaI ptg, Sheet sheet, Workbook workbook) {
|
||||
public LazyAreaEval(AreaI ptg, Sheet sheet, FormulaEvaluator evaluator) {
|
||||
super(ptg);
|
||||
_sheet = sheet;
|
||||
_workbook = workbook;
|
||||
_evaluator = evaluator;
|
||||
}
|
||||
|
||||
public ValueEval getRelativeValue(int relativeRowIndex, int relativeColumnIndex) {
|
||||
@ -53,13 +54,27 @@ public final class LazyAreaEval extends AreaEvalBase {
|
||||
if (cell == null) {
|
||||
return BlankEval.INSTANCE;
|
||||
}
|
||||
return FormulaEvaluator.getEvalForCell(cell, _sheet, _workbook);
|
||||
return _evaluator.getEvalForCell(cell, _sheet);
|
||||
}
|
||||
|
||||
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);
|
||||
return new LazyAreaEval(area, _sheet, _evaluator);
|
||||
}
|
||||
public String toString() {
|
||||
CellReference crA = new CellReference(getFirstRow(), getFirstColumn());
|
||||
CellReference crB = new CellReference(getLastRow(), getLastColumn());
|
||||
StringBuffer sb = new StringBuffer();
|
||||
sb.append(getClass().getName()).append("[");
|
||||
String sheetName = _evaluator.getSheetName(_sheet);
|
||||
sb.append(sheetName);
|
||||
sb.append('!');
|
||||
sb.append(crA.formatAsString());
|
||||
sb.append(':');
|
||||
sb.append(crB.formatAsString());
|
||||
sb.append("]");
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
||||
|
@ -1,30 +1,51 @@
|
||||
/* ====================================================================
|
||||
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.hssf.record.formula.Ref3DPtg;
|
||||
import org.apache.poi.hssf.record.formula.RefPtg;
|
||||
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;
|
||||
import org.apache.poi.ss.util.CellReference;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Josh Micich
|
||||
*/
|
||||
public final class LazyRefEval extends RefEvalBase {
|
||||
|
||||
private final Sheet _sheet;
|
||||
private final Workbook _workbook;
|
||||
private final FormulaEvaluator _evaluator;
|
||||
|
||||
|
||||
public LazyRefEval(RefPtg ptg, Sheet sheet, Workbook workbook) {
|
||||
public LazyRefEval(RefPtg ptg, Sheet sheet, FormulaEvaluator evaluator) {
|
||||
super(ptg.getRow(), ptg.getColumn());
|
||||
_sheet = sheet;
|
||||
_workbook = workbook;
|
||||
_evaluator = evaluator;
|
||||
}
|
||||
public LazyRefEval(Ref3DPtg ptg, Sheet sheet, Workbook workbook) {
|
||||
public LazyRefEval(Ref3DPtg ptg, Sheet sheet, FormulaEvaluator evaluator) {
|
||||
super(ptg.getRow(), ptg.getColumn());
|
||||
_sheet = sheet;
|
||||
_workbook = workbook;
|
||||
_evaluator = evaluator;
|
||||
}
|
||||
|
||||
public ValueEval getInnerValueEval() {
|
||||
@ -39,7 +60,7 @@ public final class LazyRefEval extends RefEvalBase {
|
||||
if (cell == null) {
|
||||
return BlankEval.INSTANCE;
|
||||
}
|
||||
return FormulaEvaluator.getEvalForCell(cell, _sheet, _workbook);
|
||||
return _evaluator.getEvalForCell(cell, _sheet);
|
||||
}
|
||||
|
||||
public AreaEval offset(int relFirstRowIx, int relLastRowIx, int relFirstColIx, int relLastColIx) {
|
||||
@ -47,6 +68,18 @@ public final class LazyRefEval extends RefEvalBase {
|
||||
AreaI area = new OffsetArea(getRow(), getColumn(),
|
||||
relFirstRowIx, relLastRowIx, relFirstColIx, relLastColIx);
|
||||
|
||||
return new LazyAreaEval(area, _sheet, _workbook);
|
||||
return new LazyAreaEval(area, _sheet, _evaluator);
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
CellReference cr = new CellReference(getRow(), getColumn());
|
||||
StringBuffer sb = new StringBuffer();
|
||||
sb.append(getClass().getName()).append("[");
|
||||
String sheetName = _evaluator.getSheetName(_sheet);
|
||||
sb.append(sheetName);
|
||||
sb.append('!');
|
||||
sb.append(cr.formatAsString());
|
||||
sb.append("]");
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
||||
|
@ -1,67 +1,34 @@
|
||||
/*
|
||||
* 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 May 8, 2005
|
||||
*
|
||||
*/
|
||||
package org.apache.poi.hssf.record.formula.eval;
|
||||
/* ====================================================================
|
||||
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
|
||||
|
||||
import org.apache.poi.hssf.record.formula.LessEqualPtg;
|
||||
import org.apache.poi.hssf.record.formula.Ptg;
|
||||
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;
|
||||
|
||||
/**
|
||||
* @author Amol S. Deshmukh < amolweb at ya hoo dot com >
|
||||
*
|
||||
*/
|
||||
public class LessEqualEval extends RelationalOperationEval {
|
||||
public final class LessEqualEval extends RelationalOperationEval {
|
||||
|
||||
private LessEqualPtg delegate;
|
||||
|
||||
public LessEqualEval(Ptg ptg) {
|
||||
this.delegate = (LessEqualPtg) ptg;
|
||||
}
|
||||
|
||||
public Eval evaluate(Eval[] operands, int srcRow, short srcCol) {
|
||||
ValueEval retval = null;
|
||||
|
||||
RelationalValues rvs = super.doEvaluate(operands, srcRow, srcCol);
|
||||
retval = rvs.ee;
|
||||
int result = 0;
|
||||
if (retval == null) {
|
||||
result = doComparison(rvs.bs);
|
||||
if (result == 0) {
|
||||
result = doComparison(rvs.ss);
|
||||
}
|
||||
if (result == 0) {
|
||||
result = doComparison(rvs.ds);
|
||||
}
|
||||
|
||||
retval = (result <= 0) ? BoolEval.TRUE : BoolEval.FALSE;;
|
||||
}
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
public int getNumberOfOperands() {
|
||||
return delegate.getNumberOfOperands();
|
||||
}
|
||||
|
||||
public int getType() {
|
||||
return delegate.getType();
|
||||
}
|
||||
public static final OperationEval instance = new LessEqualEval();
|
||||
|
||||
private LessEqualEval() {
|
||||
}
|
||||
|
||||
protected boolean convertComparisonResult(int cmpResult) {
|
||||
return cmpResult <= 0;
|
||||
}
|
||||
}
|
||||
|
@ -1,68 +1,34 @@
|
||||
/*
|
||||
* 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 May 8, 2005
|
||||
*
|
||||
*/
|
||||
package org.apache.poi.hssf.record.formula.eval;
|
||||
/* ====================================================================
|
||||
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
|
||||
|
||||
import org.apache.poi.hssf.record.formula.LessThanPtg;
|
||||
import org.apache.poi.hssf.record.formula.Ptg;
|
||||
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;
|
||||
|
||||
/**
|
||||
* @author Amol S. Deshmukh < amolweb at ya hoo dot com >
|
||||
*
|
||||
*/
|
||||
public class LessThanEval extends RelationalOperationEval {
|
||||
public final class LessThanEval extends RelationalOperationEval {
|
||||
|
||||
private LessThanPtg delegate;
|
||||
|
||||
public LessThanEval(Ptg ptg) {
|
||||
this.delegate = (LessThanPtg) ptg;
|
||||
}
|
||||
|
||||
|
||||
public Eval evaluate(Eval[] operands, int srcRow, short srcCol) {
|
||||
ValueEval retval = null;
|
||||
|
||||
RelationalValues rvs = super.doEvaluate(operands, srcRow, srcCol);
|
||||
retval = rvs.ee;
|
||||
int result = 0;
|
||||
if (retval == null) {
|
||||
result = doComparison(rvs.bs);
|
||||
if (result == 0) {
|
||||
result = doComparison(rvs.ss);
|
||||
}
|
||||
if (result == 0) {
|
||||
result = doComparison(rvs.ds);
|
||||
}
|
||||
|
||||
retval = (result < 0) ? BoolEval.TRUE : BoolEval.FALSE;;
|
||||
}
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
public int getNumberOfOperands() {
|
||||
return delegate.getNumberOfOperands();
|
||||
}
|
||||
|
||||
public int getType() {
|
||||
return delegate.getType();
|
||||
}
|
||||
public static final OperationEval instance = new LessThanEval();
|
||||
|
||||
private LessThanEval() {
|
||||
}
|
||||
|
||||
protected boolean convertComparisonResult(int cmpResult) {
|
||||
return cmpResult < 0;
|
||||
}
|
||||
}
|
||||
|
@ -1,89 +1,33 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
import org.apache.poi.hssf.record.formula.Ptg;
|
||||
import org.apache.poi.hssf.record.formula.MultiplyPtg;
|
||||
|
||||
/**
|
||||
* @author Amol S. Deshmukh < amolweb at ya hoo dot com >
|
||||
*
|
||||
*/
|
||||
public final class MultiplyEval extends NumericOperationEval {
|
||||
public final class MultiplyEval extends TwoOperandNumericOperation {
|
||||
|
||||
private MultiplyPtg delegate;
|
||||
public static final OperationEval instance = new MultiplyEval();
|
||||
|
||||
private static final ValueEvalToNumericXlator NUM_XLATOR =
|
||||
new ValueEvalToNumericXlator((short)
|
||||
( ValueEvalToNumericXlator.BOOL_IS_PARSED
|
||||
| ValueEvalToNumericXlator.REF_BOOL_IS_PARSED
|
||||
| ValueEvalToNumericXlator.STRING_IS_PARSED
|
||||
| ValueEvalToNumericXlator.REF_STRING_IS_PARSED
|
||||
));
|
||||
private MultiplyEval() {
|
||||
}
|
||||
|
||||
public MultiplyEval(Ptg ptg) {
|
||||
delegate = (MultiplyPtg) ptg;
|
||||
}
|
||||
|
||||
protected ValueEvalToNumericXlator getXlator() {
|
||||
return NUM_XLATOR;
|
||||
}
|
||||
|
||||
public Eval evaluate(Eval[] args, int srcRow, short srcCol) {
|
||||
if(args.length != 2) {
|
||||
return ErrorEval.VALUE_INVALID;
|
||||
}
|
||||
|
||||
double d0 = 0;
|
||||
double d1 = 0;
|
||||
ValueEval ve = singleOperandEvaluate(args[0], srcRow, srcCol);
|
||||
if (ve instanceof NumericValueEval) {
|
||||
d0 = ((NumericValueEval) ve).getNumberValue();
|
||||
}
|
||||
else if (ve instanceof BlankEval) {
|
||||
// do nothing
|
||||
}
|
||||
else {
|
||||
return ErrorEval.VALUE_INVALID;
|
||||
}
|
||||
|
||||
ve = singleOperandEvaluate(args[1], srcRow, srcCol);
|
||||
if (ve instanceof NumericValueEval) {
|
||||
d1 = ((NumericValueEval) ve).getNumberValue();
|
||||
}
|
||||
else if (ve instanceof BlankEval) {
|
||||
// do nothing
|
||||
}
|
||||
else {
|
||||
return ErrorEval.VALUE_INVALID;
|
||||
}
|
||||
|
||||
if (Double.isNaN(d0) || Double.isNaN(d1)) {
|
||||
return ErrorEval.NUM_ERROR;
|
||||
}
|
||||
return new NumberEval(d0 * d1);
|
||||
}
|
||||
|
||||
public int getNumberOfOperands() {
|
||||
return delegate.getNumberOfOperands();
|
||||
}
|
||||
|
||||
public int getType() {
|
||||
return delegate.getType();
|
||||
}
|
||||
protected double evaluate(double d0, double d1) {
|
||||
return d0 * d1;
|
||||
}
|
||||
}
|
||||
|
@ -22,26 +22,24 @@ package org.apache.poi.hssf.record.formula.eval;
|
||||
*/
|
||||
public final class NameEval implements Eval {
|
||||
|
||||
private final int _index;
|
||||
private final String _functionName;
|
||||
|
||||
/**
|
||||
* @param index zero based index to a defined name record
|
||||
* Creates a NameEval representing a function name
|
||||
*/
|
||||
public NameEval(int index) {
|
||||
_index = index;
|
||||
public NameEval(String functionName) {
|
||||
_functionName = functionName;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return zero based index to a defined name record
|
||||
*/
|
||||
public int getIndex() {
|
||||
return _index;
|
||||
|
||||
public String getFunctionName() {
|
||||
return _functionName;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
StringBuffer sb = new StringBuffer(64);
|
||||
sb.append(getClass().getName()).append(" [");
|
||||
sb.append(_index);
|
||||
sb.append(_functionName);
|
||||
sb.append("]");
|
||||
return sb.toString();
|
||||
}
|
||||
|
@ -1,68 +1,34 @@
|
||||
/*
|
||||
* 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 May 8, 2005
|
||||
*
|
||||
*/
|
||||
package org.apache.poi.hssf.record.formula.eval;
|
||||
/* ====================================================================
|
||||
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
|
||||
|
||||
import org.apache.poi.hssf.record.formula.NotEqualPtg;
|
||||
import org.apache.poi.hssf.record.formula.Ptg;
|
||||
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;
|
||||
|
||||
/**
|
||||
* @author Amol S. Deshmukh < amolweb at ya hoo dot com >
|
||||
*
|
||||
*/
|
||||
public class NotEqualEval extends RelationalOperationEval {
|
||||
public final class NotEqualEval extends RelationalOperationEval {
|
||||
|
||||
private NotEqualPtg delegate;
|
||||
|
||||
public NotEqualEval(Ptg ptg) {
|
||||
this.delegate = (NotEqualPtg) ptg;
|
||||
}
|
||||
|
||||
|
||||
public Eval evaluate(Eval[] operands, int srcRow, short srcCol) {
|
||||
ValueEval retval = null;
|
||||
|
||||
RelationalValues rvs = super.doEvaluate(operands, srcRow, srcCol);
|
||||
retval = rvs.ee;
|
||||
int result = 0;
|
||||
if (retval == null) {
|
||||
result = doComparison(rvs.bs);
|
||||
if (result == 0) {
|
||||
result = doComparison(rvs.ss);
|
||||
}
|
||||
if (result == 0) {
|
||||
result = doComparison(rvs.ds);
|
||||
}
|
||||
|
||||
retval = (result != 0) ? BoolEval.TRUE : BoolEval.FALSE;
|
||||
}
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
public int getNumberOfOperands() {
|
||||
return delegate.getNumberOfOperands();
|
||||
}
|
||||
|
||||
public int getType() {
|
||||
return delegate.getType();
|
||||
}
|
||||
public static final OperationEval instance = new NotEqualEval();
|
||||
|
||||
private NotEqualEval() {
|
||||
}
|
||||
|
||||
protected boolean convertComparisonResult(int cmpResult) {
|
||||
return cmpResult != 0;
|
||||
}
|
||||
}
|
||||
|
@ -1,66 +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.
|
||||
*/
|
||||
/*
|
||||
* Created on May 14, 2005
|
||||
*
|
||||
*/
|
||||
package org.apache.poi.hssf.record.formula.eval;
|
||||
|
||||
/**
|
||||
* @author Amol S. Deshmukh < amolweb at ya hoo dot com >
|
||||
*
|
||||
*/
|
||||
public abstract class NumericOperationEval implements OperationEval {
|
||||
|
||||
protected abstract ValueEvalToNumericXlator getXlator();
|
||||
|
||||
protected ValueEval singleOperandEvaluate(Eval eval, int srcRow, short srcCol) {
|
||||
ValueEval retval;
|
||||
if (eval instanceof AreaEval) {
|
||||
AreaEval ae = (AreaEval) eval;
|
||||
if (ae.contains(srcRow, srcCol)) { // circular ref!
|
||||
retval = ErrorEval.CIRCULAR_REF_ERROR;
|
||||
}
|
||||
else if (ae.isRow()) {
|
||||
if (ae.containsColumn(srcCol)) {
|
||||
ValueEval ve = ae.getValueAt(ae.getFirstRow(), srcCol);
|
||||
ve = getXlator().attemptXlateToNumeric(ve);
|
||||
retval = getXlator().attemptXlateToNumeric(ve);
|
||||
}
|
||||
else {
|
||||
retval = ErrorEval.VALUE_INVALID;
|
||||
}
|
||||
}
|
||||
else if (ae.isColumn()) {
|
||||
if (ae.containsRow(srcRow)) {
|
||||
ValueEval ve = ae.getValueAt(srcRow, ae.getFirstColumn());
|
||||
retval = getXlator().attemptXlateToNumeric(ve);
|
||||
}
|
||||
else {
|
||||
retval = ErrorEval.VALUE_INVALID;
|
||||
}
|
||||
}
|
||||
else {
|
||||
retval = ErrorEval.VALUE_INVALID;
|
||||
}
|
||||
}
|
||||
else {
|
||||
retval = getXlator().attemptXlateToNumeric((ValueEval) eval);
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
}
|
@ -17,55 +17,40 @@
|
||||
|
||||
package org.apache.poi.hssf.record.formula.eval;
|
||||
|
||||
import org.apache.poi.hssf.record.formula.PercentPtg;
|
||||
import org.apache.poi.hssf.record.formula.Ptg;
|
||||
|
||||
/**
|
||||
* Implementation of Excel formula token '%'. <p/>
|
||||
* @author Josh Micich
|
||||
*/
|
||||
public final class PercentEval extends NumericOperationEval {
|
||||
public final class PercentEval implements OperationEval {
|
||||
|
||||
private PercentPtg _delegate;
|
||||
public static final OperationEval instance = new PercentEval();
|
||||
|
||||
private static final ValueEvalToNumericXlator NUM_XLATOR = new ValueEvalToNumericXlator(
|
||||
(short) (ValueEvalToNumericXlator.BOOL_IS_PARSED
|
||||
| ValueEvalToNumericXlator.REF_BOOL_IS_PARSED
|
||||
| ValueEvalToNumericXlator.STRING_IS_PARSED | ValueEvalToNumericXlator.REF_STRING_IS_PARSED));
|
||||
|
||||
public PercentEval(Ptg ptg) {
|
||||
_delegate = (PercentPtg) ptg;
|
||||
}
|
||||
|
||||
protected ValueEvalToNumericXlator getXlator() {
|
||||
return NUM_XLATOR;
|
||||
private PercentEval() {
|
||||
}
|
||||
|
||||
public Eval evaluate(Eval[] args, int srcRow, short srcCol) {
|
||||
if (args.length != 1) {
|
||||
return ErrorEval.VALUE_INVALID;
|
||||
}
|
||||
|
||||
ValueEval ve = singleOperandEvaluate(args[0], srcRow, srcCol);
|
||||
if (ve instanceof NumericValueEval) {
|
||||
double d0 = ((NumericValueEval) ve).getNumberValue();
|
||||
return new NumberEval(d0 / 100);
|
||||
double d0;
|
||||
try {
|
||||
ValueEval ve = OperandResolver.getSingleValue(args[0], srcRow, srcCol);
|
||||
if (ve instanceof BlankEval) {
|
||||
return NumberEval.ZERO;
|
||||
}
|
||||
d0 = OperandResolver.coerceValueToDouble(ve);
|
||||
} catch (EvaluationException e) {
|
||||
return e.getErrorEval();
|
||||
}
|
||||
|
||||
if (ve instanceof BlankEval) {
|
||||
return NumberEval.ZERO;
|
||||
}
|
||||
if (ve instanceof ErrorEval) {
|
||||
return ve;
|
||||
}
|
||||
return ErrorEval.VALUE_INVALID;
|
||||
return new NumberEval(d0 / 100);
|
||||
}
|
||||
|
||||
public int getNumberOfOperands() {
|
||||
return _delegate.getNumberOfOperands();
|
||||
}
|
||||
|
||||
public int getType() {
|
||||
return _delegate.getType();
|
||||
return 1;
|
||||
}
|
||||
public final int getType() {
|
||||
// TODO - remove
|
||||
throw new RuntimeException("obsolete code should not be called");
|
||||
}
|
||||
}
|
||||
|
@ -1,90 +1,33 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
import org.apache.poi.hssf.record.formula.Ptg;
|
||||
import org.apache.poi.hssf.record.formula.PowerPtg;
|
||||
|
||||
/**
|
||||
* @author Amol S. Deshmukh < amolweb at ya hoo dot com >
|
||||
*
|
||||
*/
|
||||
public final class PowerEval extends NumericOperationEval {
|
||||
public final class PowerEval extends TwoOperandNumericOperation {
|
||||
|
||||
private PowerPtg delegate;
|
||||
public static final OperationEval instance = new PowerEval();
|
||||
|
||||
private static final ValueEvalToNumericXlator NUM_XLATOR =
|
||||
new ValueEvalToNumericXlator((short)
|
||||
( ValueEvalToNumericXlator.BOOL_IS_PARSED
|
||||
| ValueEvalToNumericXlator.REF_BOOL_IS_PARSED
|
||||
| ValueEvalToNumericXlator.STRING_IS_PARSED
|
||||
| ValueEvalToNumericXlator.REF_STRING_IS_PARSED
|
||||
));
|
||||
private PowerEval() {
|
||||
}
|
||||
|
||||
public PowerEval(Ptg ptg) {
|
||||
delegate = (PowerPtg) ptg;
|
||||
}
|
||||
|
||||
protected ValueEvalToNumericXlator getXlator() {
|
||||
return NUM_XLATOR;
|
||||
}
|
||||
|
||||
public Eval evaluate(Eval[] args, int srcRow, short srcCol) {
|
||||
if(args.length != 2) {
|
||||
return ErrorEval.VALUE_INVALID;
|
||||
}
|
||||
double d0 = 0;
|
||||
double d1 = 0;
|
||||
|
||||
ValueEval ve = singleOperandEvaluate(args[0], srcRow, srcCol);
|
||||
if (ve instanceof NumericValueEval) {
|
||||
d0 = ((NumericValueEval) ve).getNumberValue();
|
||||
}
|
||||
else if (ve instanceof BlankEval) {
|
||||
// do nothing
|
||||
}
|
||||
else {
|
||||
return ErrorEval.VALUE_INVALID;
|
||||
}
|
||||
|
||||
ve = singleOperandEvaluate(args[1], srcRow, srcCol);
|
||||
if (ve instanceof NumericValueEval) {
|
||||
d1 = ((NumericValueEval) ve).getNumberValue();
|
||||
}
|
||||
else if (ve instanceof BlankEval) {
|
||||
// do nothing
|
||||
}
|
||||
else {
|
||||
return ErrorEval.VALUE_INVALID;
|
||||
}
|
||||
|
||||
double p = Math.pow(d0, d1);
|
||||
if (Double.isNaN(p)) {
|
||||
return ErrorEval.VALUE_INVALID;
|
||||
}
|
||||
return new NumberEval(p);
|
||||
}
|
||||
|
||||
public int getNumberOfOperands() {
|
||||
return delegate.getNumberOfOperands();
|
||||
}
|
||||
|
||||
public int getType() {
|
||||
return delegate.getType();
|
||||
}
|
||||
protected double evaluate(double d0, double d1) {
|
||||
return Math.pow(d0, d1);
|
||||
}
|
||||
}
|
||||
|
@ -1,216 +1,145 @@
|
||||
/*
|
||||
* 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 May 10, 2005
|
||||
*
|
||||
*/
|
||||
/* ====================================================================
|
||||
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;
|
||||
|
||||
/**
|
||||
* Base class for all comparison operator evaluators
|
||||
*
|
||||
* @author Amol S. Deshmukh < amolweb at ya hoo dot com >
|
||||
*
|
||||
*/
|
||||
public abstract class RelationalOperationEval implements OperationEval {
|
||||
|
||||
protected class RelationalValues {
|
||||
public Double[] ds = new Double[2];
|
||||
public Boolean[] bs = new Boolean[2];
|
||||
public String[] ss = new String[3];
|
||||
public ErrorEval ee = null;
|
||||
}
|
||||
/**
|
||||
* Converts a standard compare result (-1, 0, 1) to <code>true</code> or <code>false</code>
|
||||
* according to subclass' comparison type.
|
||||
*/
|
||||
protected abstract boolean convertComparisonResult(int cmpResult);
|
||||
|
||||
|
||||
/*
|
||||
* This is a description of how the relational operators apply in MS Excel.
|
||||
* Use this as a guideline when testing/implementing the evaluate methods
|
||||
* for the relational operators Evals.
|
||||
*
|
||||
* Bool > any number. ALWAYS
|
||||
* Bool > any string. ALWAYS
|
||||
* Bool.TRUE > Bool.FALSE
|
||||
*
|
||||
* String > any number. ALWAYS
|
||||
* String > Blank. ALWAYS
|
||||
* String are sorted dictionary wise
|
||||
*
|
||||
* Blank == 0 (numeric)
|
||||
*/
|
||||
public RelationalValues doEvaluate(Eval[] operands, int srcRow, short srcCol) {
|
||||
RelationalValues retval = new RelationalValues();
|
||||
|
||||
switch (operands.length) {
|
||||
default:
|
||||
retval.ee = ErrorEval.VALUE_INVALID;
|
||||
break;
|
||||
case 2:
|
||||
internalDoEvaluate(operands, srcRow, srcCol, retval, 0);
|
||||
internalDoEvaluate(operands, srcRow, srcCol, retval, 1);
|
||||
} // end switch
|
||||
return retval;
|
||||
}
|
||||
|
||||
/**
|
||||
* convenience method to avoid code duplication for multiple operands
|
||||
* @param operands
|
||||
* @param srcRow
|
||||
* @param srcCol
|
||||
* @param retval
|
||||
* @param index
|
||||
*/
|
||||
private void internalDoEvaluate(Eval[] operands, int srcRow, short srcCol, RelationalValues retval, int index) {
|
||||
if (operands[index] instanceof BoolEval) {
|
||||
BoolEval be = (BoolEval) operands[index];
|
||||
retval.bs[index] = Boolean.valueOf(be.getBooleanValue());
|
||||
}
|
||||
else if (operands[index] instanceof NumericValueEval) {
|
||||
NumericValueEval ne = (NumericValueEval) operands[index];
|
||||
retval.ds[index] = new Double(ne.getNumberValue());
|
||||
}
|
||||
else if (operands[index] instanceof StringValueEval) {
|
||||
StringValueEval se = (StringValueEval) operands[index];
|
||||
retval.ss[index] = se.getStringValue();
|
||||
}
|
||||
else if (operands[index] instanceof RefEval) {
|
||||
RefEval re = (RefEval) operands[index];
|
||||
ValueEval ve = re.getInnerValueEval();
|
||||
if (ve instanceof BoolEval) {
|
||||
BoolEval be = (BoolEval) ve;
|
||||
retval.bs[index] = Boolean.valueOf(be.getBooleanValue());
|
||||
}
|
||||
else if (ve instanceof BlankEval) {
|
||||
retval.ds[index] = new Double(0);
|
||||
}
|
||||
else if (ve instanceof NumericValueEval) {
|
||||
NumericValueEval ne = (NumericValueEval) ve;
|
||||
retval.ds[index] = new Double(ne.getNumberValue());
|
||||
}
|
||||
else if (ve instanceof StringValueEval) {
|
||||
StringValueEval se = (StringValueEval) ve;
|
||||
retval.ss[index] = se.getStringValue();
|
||||
}
|
||||
}
|
||||
else if (operands[index] instanceof AreaEval) {
|
||||
AreaEval ae = (AreaEval) operands[index];
|
||||
if (ae.isRow()) {
|
||||
if (ae.containsColumn(srcCol)) {
|
||||
ValueEval ve = ae.getValueAt(ae.getFirstRow(), srcCol);
|
||||
if (ve instanceof BoolEval) {
|
||||
BoolEval be = (BoolEval) ve;
|
||||
retval.bs[index] = Boolean.valueOf(be.getBooleanValue());
|
||||
}
|
||||
else if (ve instanceof BlankEval) {
|
||||
retval.ds[index] = new Double(0);
|
||||
}
|
||||
else if (ve instanceof NumericValueEval) {
|
||||
NumericValueEval ne = (NumericValueEval) ve;
|
||||
retval.ds[index] = new Double(ne.getNumberValue());
|
||||
}
|
||||
else if (ve instanceof StringValueEval) {
|
||||
StringValueEval se = (StringValueEval) ve;
|
||||
retval.ss[index] = se.getStringValue();
|
||||
}
|
||||
else {
|
||||
retval.ee = ErrorEval.VALUE_INVALID;
|
||||
}
|
||||
}
|
||||
else {
|
||||
retval.ee = ErrorEval.VALUE_INVALID;
|
||||
}
|
||||
}
|
||||
else if (ae.isColumn()) {
|
||||
if (ae.containsRow(srcRow)) {
|
||||
ValueEval ve = ae.getValueAt(srcRow, ae.getFirstColumn());
|
||||
if (ve instanceof BoolEval) {
|
||||
BoolEval be = (BoolEval) ve;
|
||||
retval.bs[index] = Boolean.valueOf(be.getBooleanValue());
|
||||
}
|
||||
else if (ve instanceof BlankEval) {
|
||||
retval.ds[index] = new Double(0);
|
||||
}
|
||||
else if (ve instanceof NumericValueEval) {
|
||||
NumericValueEval ne = (NumericValueEval) ve;
|
||||
retval.ds[index] = new Double(ne.getNumberValue());
|
||||
}
|
||||
else if (ve instanceof StringValueEval) {
|
||||
StringValueEval se = (StringValueEval) ve;
|
||||
retval.ss[index] = se.getStringValue();
|
||||
}
|
||||
else {
|
||||
retval.ee = ErrorEval.VALUE_INVALID;
|
||||
}
|
||||
}
|
||||
else {
|
||||
retval.ee = ErrorEval.VALUE_INVALID;
|
||||
}
|
||||
}
|
||||
else {
|
||||
retval.ee = ErrorEval.VALUE_INVALID;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// if both null return 0, else non null wins, else TRUE wins
|
||||
protected int doComparison(Boolean[] bs) {
|
||||
int retval = 0;
|
||||
if (bs[0] != null || bs[1] != null) {
|
||||
retval = bs[0] != null
|
||||
? bs[1] != null
|
||||
? bs[0].booleanValue()
|
||||
? bs[1].booleanValue()
|
||||
? 0
|
||||
: 1
|
||||
: bs[1].booleanValue()
|
||||
? -1
|
||||
: 0
|
||||
: 1
|
||||
: bs[1] != null
|
||||
? -1
|
||||
: 0;
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
/**
|
||||
* This is a description of how the relational operators apply in MS Excel.
|
||||
* Use this as a guideline when testing/implementing the evaluate methods
|
||||
* for the relational operators Evals.
|
||||
*
|
||||
* <pre>
|
||||
* Bool.TRUE > any number.
|
||||
* Bool > any string. ALWAYS
|
||||
* Bool.TRUE > Bool.FALSE
|
||||
* Bool.FALSE == Blank
|
||||
*
|
||||
* Strings are never converted to numbers or booleans
|
||||
* String > any number. ALWAYS
|
||||
* Non-empty String > Blank
|
||||
* Empty String == Blank
|
||||
* String are sorted dictionary wise
|
||||
*
|
||||
* Blank > Negative numbers
|
||||
* Blank == 0
|
||||
* Blank < Positive numbers
|
||||
* </pre>
|
||||
*/
|
||||
public final Eval evaluate(Eval[] operands, int srcRow, short srcCol) {
|
||||
if (operands.length != 2) {
|
||||
return ErrorEval.VALUE_INVALID;
|
||||
}
|
||||
|
||||
// if both null return 0, else non null wins, else string compare
|
||||
protected int doComparison(String[] ss) {
|
||||
int retval = 0;
|
||||
if (ss[0] != null || ss[1] != null) {
|
||||
retval = ss[0] != null
|
||||
? ss[1] != null
|
||||
? ss[0].compareTo(ss[1])
|
||||
: 1
|
||||
: ss[1] != null
|
||||
? -1
|
||||
: 0;
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
ValueEval vA;
|
||||
ValueEval vB;
|
||||
try {
|
||||
vA = OperandResolver.getSingleValue(operands[0], srcRow, srcCol);
|
||||
vB = OperandResolver.getSingleValue(operands[1], srcRow, srcCol);
|
||||
} catch (EvaluationException e) {
|
||||
return e.getErrorEval();
|
||||
}
|
||||
int cmpResult = doCompare(vA, vB);
|
||||
boolean result = convertComparisonResult(cmpResult);
|
||||
return BoolEval.valueOf(result);
|
||||
}
|
||||
|
||||
// if both null return 0, else non null wins, else doublevalue compare
|
||||
protected int doComparison(Double[] ds) {
|
||||
int retval = 0;
|
||||
if (ds[0] != null || ds[1] != null) {
|
||||
retval = ds[0] != null
|
||||
? ds[1] != null
|
||||
? ds[0].compareTo(ds[1])
|
||||
: 1
|
||||
: ds[1] != null
|
||||
? -1
|
||||
: 0;
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
private static int doCompare(ValueEval va, ValueEval vb) {
|
||||
// special cases when one operand is blank
|
||||
if (va == BlankEval.INSTANCE) {
|
||||
return compareBlank(vb);
|
||||
}
|
||||
if (vb == BlankEval.INSTANCE) {
|
||||
return -compareBlank(va);
|
||||
}
|
||||
|
||||
if (va instanceof BoolEval) {
|
||||
if (vb instanceof BoolEval) {
|
||||
BoolEval bA = (BoolEval) va;
|
||||
BoolEval bB = (BoolEval) vb;
|
||||
if (bA.getBooleanValue() == bB.getBooleanValue()) {
|
||||
return 0;
|
||||
}
|
||||
return bA.getBooleanValue() ? 1 : -1;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
if (vb instanceof BoolEval) {
|
||||
return -1;
|
||||
}
|
||||
if (va instanceof StringEval) {
|
||||
if (vb instanceof StringEval) {
|
||||
StringEval sA = (StringEval) va;
|
||||
StringEval sB = (StringEval) vb;
|
||||
return sA.getStringValue().compareTo(sB.getStringValue());
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
if (vb instanceof StringEval) {
|
||||
return -1;
|
||||
}
|
||||
if (va instanceof NumberEval) {
|
||||
if (vb instanceof NumberEval) {
|
||||
NumberEval nA = (NumberEval) va;
|
||||
NumberEval nB = (NumberEval) vb;
|
||||
return Double.compare(nA.getNumberValue(), nB.getNumberValue());
|
||||
}
|
||||
}
|
||||
throw new IllegalArgumentException("Bad operand types (" + va.getClass().getName() + "), ("
|
||||
+ vb.getClass().getName() + ")");
|
||||
}
|
||||
|
||||
private static int compareBlank(ValueEval v) {
|
||||
if (v == BlankEval.INSTANCE) {
|
||||
return 0;
|
||||
}
|
||||
if (v instanceof BoolEval) {
|
||||
BoolEval boolEval = (BoolEval) v;
|
||||
return boolEval.getBooleanValue() ? -1 : 0;
|
||||
}
|
||||
if (v instanceof NumberEval) {
|
||||
NumberEval ne = (NumberEval) v;
|
||||
return Double.compare(0, ne.getNumberValue());
|
||||
}
|
||||
if (v instanceof StringEval) {
|
||||
StringEval se = (StringEval) v;
|
||||
return se.getStringValue().length() < 1 ? 0 : -1;
|
||||
}
|
||||
throw new IllegalArgumentException("bad value class (" + v.getClass().getName() + ")");
|
||||
}
|
||||
|
||||
public final int getNumberOfOperands() {
|
||||
return 2;
|
||||
}
|
||||
|
||||
public final int getType() {
|
||||
// TODO - get rid of this method
|
||||
throw new RuntimeException("Obsolete code - should not be called");
|
||||
}
|
||||
}
|
||||
|
@ -1,93 +1,33 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
import org.apache.poi.hssf.record.formula.Ptg;
|
||||
import org.apache.poi.hssf.record.formula.SubtractPtg;
|
||||
|
||||
/**
|
||||
* @author Amol S. Deshmukh < amolweb at ya hoo dot com >
|
||||
*
|
||||
*/
|
||||
public final class SubtractEval extends NumericOperationEval {
|
||||
public final class SubtractEval extends TwoOperandNumericOperation {
|
||||
|
||||
private SubtractPtg delegate;
|
||||
public static final OperationEval instance = new SubtractEval();
|
||||
|
||||
private static final ValueEvalToNumericXlator NUM_XLATOR =
|
||||
new ValueEvalToNumericXlator((short)
|
||||
( ValueEvalToNumericXlator.BOOL_IS_PARSED
|
||||
| ValueEvalToNumericXlator.REF_BOOL_IS_PARSED
|
||||
| ValueEvalToNumericXlator.STRING_IS_PARSED
|
||||
| ValueEvalToNumericXlator.REF_STRING_IS_PARSED
|
||||
));
|
||||
private SubtractEval() {
|
||||
}
|
||||
|
||||
public SubtractEval(Ptg ptg) {
|
||||
delegate = (SubtractPtg) ptg;
|
||||
}
|
||||
|
||||
protected ValueEvalToNumericXlator getXlator() {
|
||||
return NUM_XLATOR;
|
||||
}
|
||||
|
||||
public Eval evaluate(Eval[] args, int srcRow, short srcCol) {
|
||||
if(args.length != 2) {
|
||||
return ErrorEval.VALUE_INVALID;
|
||||
}
|
||||
Eval retval = null;
|
||||
double d0 = 0;
|
||||
double d1 = 0;
|
||||
ValueEval ve = singleOperandEvaluate(args[0], srcRow, srcCol);
|
||||
if (ve instanceof NumericValueEval) {
|
||||
d0 = ((NumericValueEval) ve).getNumberValue();
|
||||
}
|
||||
else if (ve instanceof BlankEval) {
|
||||
// do nothing
|
||||
}
|
||||
else {
|
||||
retval = ErrorEval.VALUE_INVALID;
|
||||
}
|
||||
|
||||
if (retval == null) { // no error yet
|
||||
ve = singleOperandEvaluate(args[1], srcRow, srcCol);
|
||||
if (ve instanceof NumericValueEval) {
|
||||
d1 = ((NumericValueEval) ve).getNumberValue();
|
||||
}
|
||||
else if (ve instanceof BlankEval) {
|
||||
// do nothing
|
||||
}
|
||||
else {
|
||||
retval = ErrorEval.VALUE_INVALID;
|
||||
}
|
||||
}
|
||||
|
||||
if (retval == null) {
|
||||
retval = (Double.isNaN(d0) || Double.isNaN(d1))
|
||||
? (ValueEval) ErrorEval.VALUE_INVALID
|
||||
: new NumberEval(d0 - d1);
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
|
||||
public int getNumberOfOperands() {
|
||||
return delegate.getNumberOfOperands();
|
||||
}
|
||||
|
||||
public int getType() {
|
||||
return delegate.getType();
|
||||
}
|
||||
protected double evaluate(double d0, double d1) {
|
||||
return d0 - d1;
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,55 @@
|
||||
/* ====================================================================
|
||||
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;
|
||||
|
||||
/**
|
||||
* @author Josh Micich
|
||||
*/
|
||||
abstract class TwoOperandNumericOperation implements OperationEval {
|
||||
|
||||
public final int getType() {
|
||||
// TODO - remove
|
||||
throw new RuntimeException("obsolete code should not be called");
|
||||
}
|
||||
protected final double singleOperandEvaluate(Eval arg, int srcCellRow, short srcCellCol) throws EvaluationException {
|
||||
ValueEval ve = OperandResolver.getSingleValue(arg, srcCellRow, srcCellCol);
|
||||
if (ve instanceof BlankEval) {
|
||||
return 0.0;
|
||||
}
|
||||
return OperandResolver.coerceValueToDouble(ve);
|
||||
}
|
||||
|
||||
public final Eval evaluate(Eval[] args, int srcCellRow, short srcCellCol) {
|
||||
double result;
|
||||
try {
|
||||
double d0 = singleOperandEvaluate(args[0], srcCellRow, srcCellCol);
|
||||
double d1 = singleOperandEvaluate(args[1], srcCellRow, srcCellCol);
|
||||
result = evaluate(d0, d1);
|
||||
if (Double.isNaN(result) || Double.isInfinite(result)) {
|
||||
return ErrorEval.NUM_ERROR;
|
||||
}
|
||||
} catch (EvaluationException e) {
|
||||
return e.getErrorEval();
|
||||
}
|
||||
return new NumberEval(result);
|
||||
}
|
||||
protected abstract double evaluate(double d0, double d1) throws EvaluationException;
|
||||
public final int getNumberOfOperands() {
|
||||
return 2;
|
||||
}
|
||||
}
|
@ -1,75 +1,56 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
import org.apache.poi.hssf.record.formula.Ptg;
|
||||
import org.apache.poi.hssf.record.formula.UnaryMinusPtg;
|
||||
|
||||
/**
|
||||
* @author Amol S. Deshmukh < amolweb at ya hoo dot com >
|
||||
*
|
||||
*/
|
||||
public final class UnaryMinusEval extends NumericOperationEval {
|
||||
public final class UnaryMinusEval implements OperationEval {
|
||||
|
||||
private UnaryMinusPtg delegate;
|
||||
private static final ValueEvalToNumericXlator NUM_XLATOR =
|
||||
new ValueEvalToNumericXlator((short)
|
||||
( ValueEvalToNumericXlator.BOOL_IS_PARSED
|
||||
| ValueEvalToNumericXlator.REF_BOOL_IS_PARSED
|
||||
| ValueEvalToNumericXlator.STRING_IS_PARSED
|
||||
| ValueEvalToNumericXlator.REF_STRING_IS_PARSED
|
||||
));
|
||||
public static final OperationEval instance = new UnaryMinusEval();
|
||||
|
||||
private UnaryMinusEval() {
|
||||
}
|
||||
|
||||
public UnaryMinusEval(Ptg ptg) {
|
||||
this.delegate = (UnaryMinusPtg) ptg;
|
||||
public Eval evaluate(Eval[] args, int srcRow, short srcCol) {
|
||||
if (args.length != 1) {
|
||||
return ErrorEval.VALUE_INVALID;
|
||||
}
|
||||
double d;
|
||||
try {
|
||||
ValueEval ve = OperandResolver.getSingleValue(args[0], srcRow, srcCol);
|
||||
if (ve instanceof BlankEval) {
|
||||
return NumberEval.ZERO;
|
||||
}
|
||||
d = OperandResolver.coerceValueToDouble(ve);
|
||||
} catch (EvaluationException e) {
|
||||
return e.getErrorEval();
|
||||
}
|
||||
return new NumberEval(-d);
|
||||
}
|
||||
|
||||
public int getNumberOfOperands() {
|
||||
return 1;
|
||||
}
|
||||
public final int getType() {
|
||||
// TODO - remove
|
||||
throw new RuntimeException("obsolete code should not be called");
|
||||
}
|
||||
|
||||
protected ValueEvalToNumericXlator getXlator() {
|
||||
return NUM_XLATOR;
|
||||
}
|
||||
|
||||
public Eval evaluate(Eval[] args, int srcRow, short srcCol) {
|
||||
if(args.length != 1) {
|
||||
return ErrorEval.VALUE_INVALID;
|
||||
}
|
||||
double d = 0;
|
||||
|
||||
ValueEval ve = singleOperandEvaluate(args[0], srcRow, srcCol);
|
||||
if (ve instanceof NumericValueEval) {
|
||||
d = ((NumericValueEval) ve).getNumberValue();
|
||||
}
|
||||
else if (ve instanceof BlankEval) {
|
||||
// do nothing
|
||||
}
|
||||
else if (ve instanceof ErrorEval) {
|
||||
return ve;
|
||||
}
|
||||
|
||||
return new NumberEval(-d);
|
||||
}
|
||||
|
||||
public int getNumberOfOperands() {
|
||||
return delegate.getNumberOfOperands();
|
||||
}
|
||||
|
||||
public int getType() {
|
||||
return delegate.getType();
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -17,8 +17,6 @@
|
||||
|
||||
package org.apache.poi.hssf.record.formula.eval;
|
||||
|
||||
import org.apache.poi.hssf.record.formula.Ptg;
|
||||
import org.apache.poi.hssf.record.formula.UnaryPlusPtg;
|
||||
|
||||
/**
|
||||
* @author Amol S. Deshmukh < amolweb at ya hoo dot com >
|
||||
@ -26,13 +24,9 @@ import org.apache.poi.hssf.record.formula.UnaryPlusPtg;
|
||||
*/
|
||||
public final class UnaryPlusEval implements OperationEval {
|
||||
|
||||
private UnaryPlusPtg delegate;
|
||||
public static final OperationEval instance = new UnaryPlusEval();
|
||||
|
||||
/**
|
||||
* called by reflection
|
||||
*/
|
||||
public UnaryPlusEval(Ptg ptg) {
|
||||
this.delegate = (UnaryPlusPtg) ptg;
|
||||
private UnaryPlusEval() {
|
||||
}
|
||||
|
||||
public Eval evaluate(Eval[] args, int srcCellRow, short srcCellCol) {
|
||||
@ -59,10 +53,10 @@ public final class UnaryPlusEval implements OperationEval {
|
||||
}
|
||||
|
||||
public int getNumberOfOperands() {
|
||||
return delegate.getNumberOfOperands();
|
||||
return 1;
|
||||
}
|
||||
|
||||
public int getType() {
|
||||
return delegate.getType();
|
||||
throw new RuntimeException("obsolete code should not be called");
|
||||
}
|
||||
}
|
||||
|
@ -55,49 +55,40 @@ public final class ValueEvalToNumericXlator {
|
||||
* @param eval
|
||||
*/
|
||||
public ValueEval attemptXlateToNumeric(ValueEval eval) {
|
||||
ValueEval retval = null;
|
||||
|
||||
if (eval == null) {
|
||||
retval = BlankEval.INSTANCE;
|
||||
throw new IllegalArgumentException("eval must not be null");
|
||||
}
|
||||
|
||||
// most common case - least worries :)
|
||||
else if (eval instanceof NumberEval) {
|
||||
retval = eval;
|
||||
if (eval instanceof NumberEval) {
|
||||
return eval;
|
||||
}
|
||||
|
||||
// booleval
|
||||
else if (eval instanceof BoolEval) {
|
||||
retval = ((flags & BOOL_IS_PARSED) > 0)
|
||||
if (eval instanceof BoolEval) {
|
||||
return ((flags & BOOL_IS_PARSED) > 0)
|
||||
? (NumericValueEval) eval
|
||||
: xlateBlankEval(BLANK_IS_PARSED);
|
||||
}
|
||||
|
||||
// stringeval
|
||||
else if (eval instanceof StringEval) {
|
||||
retval = xlateStringEval((StringEval) eval); // TODO: recursive call needed
|
||||
if (eval instanceof StringEval) {
|
||||
return xlateStringEval((StringEval) eval); // TODO: recursive call needed
|
||||
}
|
||||
|
||||
// refeval
|
||||
else if (eval instanceof RefEval) {
|
||||
retval = xlateRefEval((RefEval) eval);
|
||||
if (eval instanceof RefEval) {
|
||||
return xlateRefEval((RefEval) eval);
|
||||
}
|
||||
|
||||
// erroreval
|
||||
else if (eval instanceof ErrorEval) {
|
||||
retval = eval;
|
||||
if (eval instanceof ErrorEval) {
|
||||
return eval;
|
||||
}
|
||||
|
||||
else if (eval instanceof BlankEval) {
|
||||
retval = xlateBlankEval(BLANK_IS_PARSED);
|
||||
if (eval instanceof BlankEval) {
|
||||
return xlateBlankEval(BLANK_IS_PARSED);
|
||||
}
|
||||
|
||||
// probably AreaEval? then not acceptable.
|
||||
else {
|
||||
throw new RuntimeException("Invalid ValueEval type passed for conversion: " + eval.getClass());
|
||||
}
|
||||
|
||||
return retval;
|
||||
throw new RuntimeException("Invalid ValueEval type passed for conversion: " + eval.getClass());
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -60,8 +60,7 @@ public final class Hlookup implements Function {
|
||||
AreaEval tableArray = LookupUtils.resolveTableArrayArg(args[1]);
|
||||
boolean isRangeLookup = LookupUtils.resolveRangeLookupArg(arg3, srcCellRow, srcCellCol);
|
||||
int colIndex = LookupUtils.lookupIndexOfValue(lookupValue, LookupUtils.createRowVector(tableArray, 0), isRangeLookup);
|
||||
ValueEval veColIndex = OperandResolver.getSingleValue(args[2], srcCellRow, srcCellCol);
|
||||
int rowIndex = LookupUtils.resolveRowOrColIndexArg(veColIndex);
|
||||
int rowIndex = LookupUtils.resolveRowOrColIndexArg(args[2], srcCellRow, srcCellCol);
|
||||
ValueVector resultCol = createResultColumnVector(tableArray, rowIndex);
|
||||
return resultCol.getItem(colIndex);
|
||||
} catch (EvaluationException e) {
|
||||
@ -73,15 +72,14 @@ public final class Hlookup implements Function {
|
||||
/**
|
||||
* Returns one column from an <tt>AreaEval</tt>
|
||||
*
|
||||
* @throws EvaluationException (#VALUE!) if colIndex is negative, (#REF!) if colIndex is too high
|
||||
* @param rowIndex assumed to be non-negative
|
||||
*
|
||||
* @throws EvaluationException (#REF!) if colIndex is too high
|
||||
*/
|
||||
private ValueVector createResultColumnVector(AreaEval tableArray, int colIndex) throws EvaluationException {
|
||||
if(colIndex < 0) {
|
||||
throw EvaluationException.invalidValue();
|
||||
}
|
||||
if(colIndex >= tableArray.getWidth()) {
|
||||
private ValueVector createResultColumnVector(AreaEval tableArray, int rowIndex) throws EvaluationException {
|
||||
if(rowIndex >= tableArray.getHeight()) {
|
||||
throw EvaluationException.invalidRef();
|
||||
}
|
||||
return LookupUtils.createRowVector(tableArray, colIndex);
|
||||
return LookupUtils.createRowVector(tableArray, rowIndex);
|
||||
}
|
||||
}
|
||||
|
@ -322,30 +322,45 @@ final class LookupUtils {
|
||||
* <tr><td><blank></td><td> </td><td>#VALUE!</td></tr>
|
||||
* </table><br/>
|
||||
*
|
||||
* * Note - out of range errors (both too high and too low) are handled by the caller.
|
||||
* @return column or row index as a zero-based value
|
||||
*
|
||||
* Note - out of range errors (result index too high) are handled by the caller.
|
||||
* @return column or row index as a zero-based value, never negative.
|
||||
* @throws EvaluationException when the specified arg cannot be coerced to a non-negative integer
|
||||
*/
|
||||
public static int resolveRowOrColIndexArg(ValueEval veRowColIndexArg) throws EvaluationException {
|
||||
if(veRowColIndexArg == null) {
|
||||
public static int resolveRowOrColIndexArg(Eval rowColIndexArg, int srcCellRow, int srcCellCol) throws EvaluationException {
|
||||
if(rowColIndexArg == null) {
|
||||
throw new IllegalArgumentException("argument must not be null");
|
||||
}
|
||||
|
||||
ValueEval veRowColIndexArg;
|
||||
try {
|
||||
veRowColIndexArg = OperandResolver.getSingleValue(rowColIndexArg, srcCellRow, (short)srcCellCol);
|
||||
} catch (EvaluationException e) {
|
||||
// All errors get translated to #REF!
|
||||
throw EvaluationException.invalidRef();
|
||||
}
|
||||
int oneBasedIndex;
|
||||
if(veRowColIndexArg instanceof BlankEval) {
|
||||
oneBasedIndex = 0;
|
||||
} else {
|
||||
if(veRowColIndexArg instanceof StringEval) {
|
||||
StringEval se = (StringEval) veRowColIndexArg;
|
||||
String strVal = se.getStringValue();
|
||||
Double dVal = OperandResolver.parseDouble(strVal);
|
||||
if(dVal == null) {
|
||||
// String does not resolve to a number. Raise #REF! error.
|
||||
throw EvaluationException.invalidRef();
|
||||
// This includes text booleans "TRUE" and "FALSE". They are not valid.
|
||||
}
|
||||
// else - numeric value parses OK
|
||||
}
|
||||
// actual BoolEval values get interpreted as FALSE->0 and TRUE->1
|
||||
oneBasedIndex = OperandResolver.coerceValueToInt(veRowColIndexArg);
|
||||
}
|
||||
if (oneBasedIndex < 1) {
|
||||
// note this is asymmetric with the errors when the index is too large (#REF!)
|
||||
throw EvaluationException.invalidValue();
|
||||
}
|
||||
if(veRowColIndexArg instanceof StringEval) {
|
||||
StringEval se = (StringEval) veRowColIndexArg;
|
||||
String strVal = se.getStringValue();
|
||||
Double dVal = OperandResolver.parseDouble(strVal);
|
||||
if(dVal == null) {
|
||||
// String does not resolve to a number. Raise #VALUE! error.
|
||||
throw EvaluationException.invalidRef();
|
||||
// This includes text booleans "TRUE" and "FALSE". They are not valid.
|
||||
}
|
||||
// else - numeric value parses OK
|
||||
}
|
||||
// actual BoolEval values get interpreted as FALSE->0 and TRUE->1
|
||||
return OperandResolver.coerceValueToInt(veRowColIndexArg) - 1;
|
||||
return oneBasedIndex - 1; // convert to zero based
|
||||
}
|
||||
|
||||
|
||||
@ -583,11 +598,13 @@ final class LookupUtils {
|
||||
return maxIx - 1;
|
||||
}
|
||||
|
||||
public static LookupValueComparer createLookupComparer(ValueEval lookupValue) throws EvaluationException {
|
||||
public static LookupValueComparer createLookupComparer(ValueEval lookupValue) {
|
||||
|
||||
if (lookupValue instanceof BlankEval) {
|
||||
// blank eval can never be found in a lookup array
|
||||
throw new EvaluationException(ErrorEval.NA);
|
||||
if (lookupValue == BlankEval.INSTANCE) {
|
||||
// blank eval translates to zero
|
||||
// Note - a blank eval in the lookup column/row never matches anything
|
||||
// empty string in the lookup column/row can only be matched by explicit emtpty string
|
||||
return new NumberLookupComparer(NumberEval.ZERO);
|
||||
}
|
||||
if (lookupValue instanceof StringEval) {
|
||||
return new StringLookupComparer((StringEval) lookupValue);
|
||||
|
@ -60,8 +60,7 @@ public final class Vlookup implements Function {
|
||||
AreaEval tableArray = LookupUtils.resolveTableArrayArg(args[1]);
|
||||
boolean isRangeLookup = LookupUtils.resolveRangeLookupArg(arg3, srcCellRow, srcCellCol);
|
||||
int rowIndex = LookupUtils.lookupIndexOfValue(lookupValue, LookupUtils.createColumnVector(tableArray, 0), isRangeLookup);
|
||||
ValueEval veColIndex = OperandResolver.getSingleValue(args[2], srcCellRow, srcCellCol);
|
||||
int colIndex = LookupUtils.resolveRowOrColIndexArg(veColIndex);
|
||||
int colIndex = LookupUtils.resolveRowOrColIndexArg(args[2], srcCellRow, srcCellCol);
|
||||
ValueVector resultCol = createResultColumnVector(tableArray, colIndex);
|
||||
return resultCol.getItem(rowIndex);
|
||||
} catch (EvaluationException e) {
|
||||
@ -73,12 +72,11 @@ public final class Vlookup implements Function {
|
||||
/**
|
||||
* Returns one column from an <tt>AreaEval</tt>
|
||||
*
|
||||
* @throws EvaluationException (#VALUE!) if colIndex is negative, (#REF!) if colIndex is too high
|
||||
* @param colIndex assumed to be non-negative
|
||||
*
|
||||
* @throws EvaluationException (#REF!) if colIndex is too high
|
||||
*/
|
||||
private ValueVector createResultColumnVector(AreaEval tableArray, int colIndex) throws EvaluationException {
|
||||
if(colIndex < 0) {
|
||||
throw EvaluationException.invalidValue();
|
||||
}
|
||||
if(colIndex >= tableArray.getWidth()) {
|
||||
throw EvaluationException.invalidRef();
|
||||
}
|
||||
|
@ -23,15 +23,15 @@ import org.apache.poi.hssf.util.RangeAddress;
|
||||
import org.apache.poi.ss.usermodel.Name;
|
||||
|
||||
/**
|
||||
* High Level Representation of a 'defined name' which could be a 'built-in' name,
|
||||
* High Level Representation of a 'defined name' which could be a 'built-in' name,
|
||||
* 'named range' or name of a user defined function.
|
||||
*
|
||||
*
|
||||
* @author Libin Roman (Vista Portal LDT. Developer)
|
||||
*/
|
||||
public class HSSFName implements Name {
|
||||
private HSSFWorkbook _book;
|
||||
private NameRecord _definedNameRec;
|
||||
|
||||
|
||||
/** Creates new HSSFName - called by HSSFWorkbook to create a sheet from
|
||||
* scratch.
|
||||
*
|
||||
@ -43,58 +43,57 @@ public class HSSFName implements Name {
|
||||
_book = book;
|
||||
_definedNameRec = name;
|
||||
}
|
||||
|
||||
|
||||
/** Get the sheets name which this named range is referenced to
|
||||
* @return sheet name, which this named range referred to
|
||||
*/
|
||||
*/
|
||||
public String getSheetName() {
|
||||
short indexToExternSheet = _definedNameRec.getExternSheetNumber();
|
||||
|
||||
|
||||
return _book.getWorkbook().findSheetNameFromExternSheet(indexToExternSheet);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
/**
|
||||
* @return text name of this defined name
|
||||
*/
|
||||
*/
|
||||
public String getNameName(){
|
||||
return _definedNameRec.getNameText();
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
/**
|
||||
* sets the name of the named range
|
||||
* @param nameName named range name to set
|
||||
*/
|
||||
*/
|
||||
public void setNameName(String nameName){
|
||||
_definedNameRec.setNameText(nameName);
|
||||
_definedNameRec.setNameTextLength((byte)nameName.length());
|
||||
Workbook wb = _book.getWorkbook();
|
||||
|
||||
|
||||
//Check to ensure no other names have the same case-insensitive name
|
||||
for ( int i = wb.getNumNames()-1; i >=0; i-- )
|
||||
{
|
||||
NameRecord rec = wb.getNameRecord(i);
|
||||
if (rec != _definedNameRec) {
|
||||
if (rec.getNameText().equalsIgnoreCase(getNameName()))
|
||||
throw new IllegalArgumentException("The workbook already contains this name (case-insensitive)");
|
||||
}
|
||||
NameRecord rec = wb.getNameRecord(i);
|
||||
if (rec != _definedNameRec) {
|
||||
if (rec.getNameText().equalsIgnoreCase(getNameName()))
|
||||
throw new IllegalArgumentException("The workbook already contains this name (case-insensitive)");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
/**
|
||||
* Note - this method only applies to named ranges
|
||||
* @return the formula text defining the named range
|
||||
*/
|
||||
*/
|
||||
public String getReference() {
|
||||
if (_definedNameRec.isFunctionName()) {
|
||||
throw new IllegalStateException("Only applicable to named ranges");
|
||||
}
|
||||
if (_definedNameRec.isFunctionName()) {
|
||||
throw new IllegalStateException("Only applicable to named ranges");
|
||||
}
|
||||
return _definedNameRec.getAreaReference(_book);
|
||||
}
|
||||
|
||||
/**
|
||||
/**
|
||||
* sets the sheet name which this named range referenced to
|
||||
* @param sheetName the sheet name of the reference
|
||||
*/
|
||||
*/
|
||||
private void setSheetName(String sheetName){
|
||||
int sheetNumber = _book.getSheetIndex(sheetName);
|
||||
short externSheetNumber = (short)
|
||||
@ -102,11 +101,11 @@ public class HSSFName implements Name {
|
||||
_definedNameRec.setExternSheetNumber(externSheetNumber);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
|
||||
/**
|
||||
* sets the reference of this named range
|
||||
* @param ref the reference to set
|
||||
*/
|
||||
*/
|
||||
public void setReference(String ref){
|
||||
|
||||
RangeAddress ra = new RangeAddress(ref);
|
||||
@ -117,7 +116,7 @@ public class HSSFName implements Name {
|
||||
setSheetName(sheetName);
|
||||
}
|
||||
|
||||
//allow the poi utilities to parse it out
|
||||
//allow the poi utilities to parse it out
|
||||
_definedNameRec.setAreaReference(ref);
|
||||
}
|
||||
|
||||
@ -131,7 +130,7 @@ public class HSSFName implements Name {
|
||||
return "#REF!".endsWith(ref);
|
||||
}
|
||||
public boolean isFunctionName() {
|
||||
return _definedNameRec.isFunctionName();
|
||||
return _definedNameRec.isFunctionName();
|
||||
}
|
||||
public String toString() {
|
||||
StringBuffer sb = new StringBuffer(64);
|
||||
|
@ -27,7 +27,6 @@ import java.util.ArrayList;
|
||||
import java.util.Hashtable;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Stack;
|
||||
|
||||
import org.apache.poi.POIDocument;
|
||||
import org.apache.poi.ddf.EscherBSERecord;
|
||||
@ -36,6 +35,7 @@ import org.apache.poi.ddf.EscherBlipRecord;
|
||||
import org.apache.poi.ddf.EscherRecord;
|
||||
import org.apache.poi.hssf.model.Sheet;
|
||||
import org.apache.poi.hssf.model.Workbook;
|
||||
import org.apache.poi.hssf.model.DrawingManager2;
|
||||
import org.apache.poi.hssf.record.AbstractEscherHolderRecord;
|
||||
import org.apache.poi.hssf.record.BackupRecord;
|
||||
import org.apache.poi.hssf.record.DrawingGroupRecord;
|
||||
@ -55,6 +55,8 @@ import org.apache.poi.hssf.record.aggregates.RecordAggregate.RecordVisitor;
|
||||
import org.apache.poi.hssf.record.formula.Area3DPtg;
|
||||
import org.apache.poi.hssf.record.formula.MemFuncPtg;
|
||||
import org.apache.poi.hssf.record.formula.NameXPtg;
|
||||
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.util.CellReference;
|
||||
import org.apache.poi.hssf.util.SheetReferences;
|
||||
@ -667,33 +669,81 @@ public class HSSFWorkbook extends POIDocument implements org.apache.poi.ss.userm
|
||||
* @return HSSFSheet representing the cloned sheet.
|
||||
*/
|
||||
|
||||
public HSSFSheet cloneSheet(int sheetNum) {
|
||||
validateSheetIndex(sheetNum);
|
||||
HSSFSheet srcSheet = (HSSFSheet) _sheets.get(sheetNum);
|
||||
String srcName = workbook.getSheetName(sheetNum);
|
||||
public HSSFSheet cloneSheet(int sheetIndex) {
|
||||
validateSheetIndex(sheetIndex);
|
||||
HSSFSheet srcSheet = (HSSFSheet) _sheets.get(sheetIndex);
|
||||
String srcName = workbook.getSheetName(sheetIndex);
|
||||
HSSFSheet clonedSheet = srcSheet.cloneSheet(this);
|
||||
clonedSheet.setSelected(false);
|
||||
clonedSheet.setActive(false);
|
||||
|
||||
String name = getUniqueSheetName(srcName);
|
||||
int newSheetIndex = _sheets.size();
|
||||
_sheets.add(clonedSheet);
|
||||
int i = 1;
|
||||
workbook.setSheetName(newSheetIndex, name);
|
||||
|
||||
// Check this sheet has an autofilter, (which has a built-in NameRecord at workbook level)
|
||||
int filterDbNameIndex = findExistingBuiltinNameRecordIdx(sheetIndex, NameRecord.BUILTIN_FILTER_DB);
|
||||
if (filterDbNameIndex >=0) {
|
||||
NameRecord origNameRecord = workbook.getNameRecord(filterDbNameIndex);
|
||||
// copy original formula but adjust 3D refs to the new external sheet index
|
||||
int newExtSheetIx = getExternalSheetIndex(newSheetIndex);
|
||||
Ptg[] ptgs = origNameRecord.getNameDefinition();
|
||||
for (int i=0; i< ptgs.length; i++) {
|
||||
Ptg ptg = ptgs[i];
|
||||
ptg = ptg.copy();
|
||||
|
||||
if (ptg instanceof Area3DPtg) {
|
||||
Area3DPtg a3p = (Area3DPtg) ptg;
|
||||
a3p.setExternSheetIndex(newExtSheetIx);
|
||||
} else if (ptg instanceof Ref3DPtg) {
|
||||
Ref3DPtg r3p = (Ref3DPtg) ptg;
|
||||
r3p.setExternSheetIndex(newExtSheetIx);
|
||||
}
|
||||
ptgs[i] = ptg;
|
||||
}
|
||||
NameRecord newNameRecord = workbook.createBuiltInName(NameRecord.BUILTIN_FILTER_DB, newSheetIndex+1);
|
||||
newNameRecord.setNameDefinition(ptgs);
|
||||
newNameRecord.setHidden(true);
|
||||
HSSFName newName = new HSSFName(this, newNameRecord);
|
||||
names.add(newName);
|
||||
|
||||
workbook.cloneDrawings(clonedSheet.getSheet());
|
||||
}
|
||||
// TODO - maybe same logic required for other/all built-in name records
|
||||
|
||||
return clonedSheet;
|
||||
}
|
||||
|
||||
private String getUniqueSheetName(String srcName) {
|
||||
int uniqueIndex = 2;
|
||||
String baseName = srcName;
|
||||
int bracketPos = srcName.lastIndexOf('(');
|
||||
if (bracketPos > 0 && srcName.endsWith(")")) {
|
||||
String suffix = srcName.substring(bracketPos + 1, srcName.length() - ")".length());
|
||||
try {
|
||||
uniqueIndex = Integer.parseInt(suffix.trim());
|
||||
uniqueIndex++;
|
||||
baseName=srcName.substring(0, bracketPos).trim();
|
||||
} catch (NumberFormatException e) {
|
||||
// contents of brackets not numeric
|
||||
}
|
||||
}
|
||||
while (true) {
|
||||
// Try and find the next sheet name that is unique
|
||||
String name = srcName;
|
||||
String index = Integer.toString(i++);
|
||||
if (name.length() + index.length() + 2 < 31) {
|
||||
name = name + "(" + index + ")";
|
||||
String index = Integer.toString(uniqueIndex++);
|
||||
String name;
|
||||
if (baseName.length() + index.length() + 2 < 31) {
|
||||
name = baseName + " (" + index + ")";
|
||||
} else {
|
||||
name = name.substring(0, 31 - index.length() - 2) + "(" + index + ")";
|
||||
name = baseName.substring(0, 31 - index.length() - 2) + "(" + index + ")";
|
||||
}
|
||||
|
||||
//If the sheet name is unique, then set it otherwise move on to the next number.
|
||||
if (workbook.getSheetIndex(name) == -1) {
|
||||
workbook.setSheetName(_sheets.size()-1, name);
|
||||
break;
|
||||
return name;
|
||||
}
|
||||
}
|
||||
return clonedSheet;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -907,7 +957,7 @@ public class HSSFWorkbook extends POIDocument implements org.apache.poi.ss.userm
|
||||
boolean removingRange =
|
||||
startColumn == -1 && endColumn == -1 && startRow == -1 && endRow == -1;
|
||||
|
||||
int rowColHeaderNameIndex = findExistingRowColHeaderNameRecordIdx(sheetIndex);
|
||||
int rowColHeaderNameIndex = findExistingBuiltinNameRecordIdx(sheetIndex, NameRecord.BUILTIN_PRINT_TITLE);
|
||||
if (removingRange) {
|
||||
if (rowColHeaderNameIndex >= 0) {
|
||||
workbook.removeName(rowColHeaderNameIndex);
|
||||
@ -925,29 +975,27 @@ public class HSSFWorkbook extends POIDocument implements org.apache.poi.ss.userm
|
||||
isNewRecord = false;
|
||||
}
|
||||
|
||||
short definitionTextLength = settingRowAndColumn ? (short)0x001a : (short)0x000b;
|
||||
nameRecord.setDefinitionTextLength(definitionTextLength); // TODO - remove
|
||||
|
||||
Stack ptgs = new Stack();
|
||||
List temp = new ArrayList();
|
||||
|
||||
if (settingRowAndColumn) {
|
||||
final int exprsSize = 2 * 11 + 1; // 2 * Area3DPtg.SIZE + UnionPtg.SIZE
|
||||
ptgs.add(new MemFuncPtg(exprsSize));
|
||||
temp.add(new MemFuncPtg(exprsSize));
|
||||
}
|
||||
if (startColumn >= 0) {
|
||||
Area3DPtg colArea = new Area3DPtg(0, MAX_ROW, startColumn, endColumn,
|
||||
false, false, false, false, externSheetIndex);
|
||||
ptgs.add(colArea);
|
||||
temp.add(colArea);
|
||||
}
|
||||
if (startRow >= 0) {
|
||||
Area3DPtg rowArea = new Area3DPtg(startRow, endRow, 0, MAX_COLUMN,
|
||||
false, false, false, false, externSheetIndex);
|
||||
ptgs.add(rowArea);
|
||||
temp.add(rowArea);
|
||||
}
|
||||
if (settingRowAndColumn)
|
||||
{
|
||||
ptgs.add(UnionPtg.instance);
|
||||
if (settingRowAndColumn) {
|
||||
temp.add(UnionPtg.instance);
|
||||
}
|
||||
Ptg[] ptgs = new Ptg[temp.size()];
|
||||
temp.toArray(ptgs);
|
||||
nameRecord.setNameDefinition(ptgs);
|
||||
|
||||
if (isNewRecord)
|
||||
@ -963,13 +1011,13 @@ public class HSSFWorkbook extends POIDocument implements org.apache.poi.ss.userm
|
||||
}
|
||||
|
||||
|
||||
private int findExistingRowColHeaderNameRecordIdx(int sheetIndex) {
|
||||
private int findExistingBuiltinNameRecordIdx(int sheetIndex, byte builtinCode) {
|
||||
for(int defNameIndex =0; defNameIndex<names.size(); defNameIndex++) {
|
||||
NameRecord r = workbook.getNameRecord(defNameIndex);
|
||||
if (r == null) {
|
||||
throw new RuntimeException("Unable to find all defined names to iterate over");
|
||||
}
|
||||
if (!isRowColHeaderRecord( r )) {
|
||||
if (!r.isBuiltInName() || r.getBuiltInName() != builtinCode) {
|
||||
continue;
|
||||
}
|
||||
if(r.getSheetNumber() == 0) {
|
||||
@ -985,10 +1033,6 @@ public class HSSFWorkbook extends POIDocument implements org.apache.poi.ss.userm
|
||||
return -1;
|
||||
}
|
||||
|
||||
private static boolean isRowColHeaderRecord(NameRecord r) {
|
||||
return r.isBuiltInName() && r.getBuiltInName() == NameRecord.BUILTIN_PRINT_TITLE;
|
||||
}
|
||||
|
||||
/**
|
||||
* create a new Font and add it to the workbook's font table
|
||||
* @return new font object
|
||||
@ -1288,6 +1332,9 @@ public class HSSFWorkbook extends POIDocument implements org.apache.poi.ss.userm
|
||||
|
||||
return result;
|
||||
}
|
||||
public NameRecord getNameRecord(int nameIndex) {
|
||||
return getWorkbook().getNameRecord(nameIndex);
|
||||
}
|
||||
|
||||
/** gets the named range name
|
||||
* @param index the named range index (0 based)
|
||||
|
184
src/java/org/apache/poi/hssf/usermodel/OperationEvaluatorFactory.java
Executable file
184
src/java/org/apache/poi/hssf/usermodel/OperationEvaluatorFactory.java
Executable file
@ -0,0 +1,184 @@
|
||||
/* ====================================================================
|
||||
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.usermodel;
|
||||
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.poi.hssf.record.formula.AddPtg;
|
||||
import org.apache.poi.hssf.record.formula.ConcatPtg;
|
||||
import org.apache.poi.hssf.record.formula.DividePtg;
|
||||
import org.apache.poi.hssf.record.formula.EqualPtg;
|
||||
import org.apache.poi.hssf.record.formula.ExpPtg;
|
||||
import org.apache.poi.hssf.record.formula.FuncPtg;
|
||||
import org.apache.poi.hssf.record.formula.FuncVarPtg;
|
||||
import org.apache.poi.hssf.record.formula.GreaterEqualPtg;
|
||||
import org.apache.poi.hssf.record.formula.GreaterThanPtg;
|
||||
import org.apache.poi.hssf.record.formula.LessEqualPtg;
|
||||
import org.apache.poi.hssf.record.formula.LessThanPtg;
|
||||
import org.apache.poi.hssf.record.formula.MultiplyPtg;
|
||||
import org.apache.poi.hssf.record.formula.NotEqualPtg;
|
||||
import org.apache.poi.hssf.record.formula.OperationPtg;
|
||||
import org.apache.poi.hssf.record.formula.PercentPtg;
|
||||
import org.apache.poi.hssf.record.formula.PowerPtg;
|
||||
import org.apache.poi.hssf.record.formula.Ptg;
|
||||
import org.apache.poi.hssf.record.formula.SubtractPtg;
|
||||
import org.apache.poi.hssf.record.formula.UnaryMinusPtg;
|
||||
import org.apache.poi.hssf.record.formula.UnaryPlusPtg;
|
||||
import org.apache.poi.hssf.record.formula.eval.AddEval;
|
||||
import org.apache.poi.hssf.record.formula.eval.ConcatEval;
|
||||
import org.apache.poi.hssf.record.formula.eval.DivideEval;
|
||||
import org.apache.poi.hssf.record.formula.eval.EqualEval;
|
||||
import org.apache.poi.hssf.record.formula.eval.FuncVarEval;
|
||||
import org.apache.poi.hssf.record.formula.eval.GreaterEqualEval;
|
||||
import org.apache.poi.hssf.record.formula.eval.GreaterThanEval;
|
||||
import org.apache.poi.hssf.record.formula.eval.LessEqualEval;
|
||||
import org.apache.poi.hssf.record.formula.eval.LessThanEval;
|
||||
import org.apache.poi.hssf.record.formula.eval.MultiplyEval;
|
||||
import org.apache.poi.hssf.record.formula.eval.NotEqualEval;
|
||||
import org.apache.poi.hssf.record.formula.eval.OperationEval;
|
||||
import org.apache.poi.hssf.record.formula.eval.PercentEval;
|
||||
import org.apache.poi.hssf.record.formula.eval.PowerEval;
|
||||
import org.apache.poi.hssf.record.formula.eval.SubtractEval;
|
||||
import org.apache.poi.hssf.record.formula.eval.UnaryMinusEval;
|
||||
import org.apache.poi.hssf.record.formula.eval.UnaryPlusEval;
|
||||
|
||||
/**
|
||||
* This class creates <tt>OperationEval</tt> instances to help evaluate <tt>OperationPtg</tt>
|
||||
* formula tokens.
|
||||
*
|
||||
* @author Josh Micich
|
||||
*/
|
||||
final class OperationEvaluatorFactory {
|
||||
private static final Class[] OPERATION_CONSTRUCTOR_CLASS_ARRAY = new Class[] { Ptg.class };
|
||||
// TODO - use singleton instances directly instead of reflection
|
||||
private static final Map _constructorsByPtgClass = initialiseConstructorsMap();
|
||||
private static final Map _instancesByPtgClass = initialiseInstancesMap();
|
||||
|
||||
private OperationEvaluatorFactory() {
|
||||
// no instances of this class
|
||||
}
|
||||
|
||||
private static Map initialiseConstructorsMap() {
|
||||
Map m = new HashMap(32);
|
||||
add(m, ConcatPtg.class, ConcatEval.class);
|
||||
add(m, FuncPtg.class, FuncVarEval.class);
|
||||
add(m, FuncVarPtg.class, FuncVarEval.class);
|
||||
return m;
|
||||
}
|
||||
private static Map initialiseInstancesMap() {
|
||||
Map m = new HashMap(32);
|
||||
add(m, EqualPtg.class, EqualEval.instance);
|
||||
add(m, GreaterEqualPtg.class, GreaterEqualEval.instance);
|
||||
add(m, GreaterThanPtg.class, GreaterThanEval.instance);
|
||||
add(m, LessEqualPtg.class, LessEqualEval.instance);
|
||||
add(m, LessThanPtg.class, LessThanEval.instance);
|
||||
add(m, NotEqualPtg.class, NotEqualEval.instance);
|
||||
|
||||
add(m, AddPtg.class, AddEval.instance);
|
||||
add(m, DividePtg.class, DivideEval.instance);
|
||||
add(m, MultiplyPtg.class, MultiplyEval.instance);
|
||||
add(m, PercentPtg.class, PercentEval.instance);
|
||||
add(m, PowerPtg.class, PowerEval.instance);
|
||||
add(m, SubtractPtg.class, SubtractEval.instance);
|
||||
add(m, UnaryMinusPtg.class, UnaryMinusEval.instance);
|
||||
add(m, UnaryPlusPtg.class, UnaryPlusEval.instance);
|
||||
return m;
|
||||
}
|
||||
|
||||
private static void add(Map m, Class ptgClass, OperationEval evalInstance) {
|
||||
if(!Ptg.class.isAssignableFrom(ptgClass)) {
|
||||
throw new IllegalArgumentException("Expected Ptg subclass");
|
||||
}
|
||||
m.put(ptgClass, evalInstance);
|
||||
}
|
||||
|
||||
private static void add(Map m, Class ptgClass, Class evalClass) {
|
||||
// perform some validation now, to keep later exception handlers simple
|
||||
if(!Ptg.class.isAssignableFrom(ptgClass)) {
|
||||
throw new IllegalArgumentException("Expected Ptg subclass");
|
||||
}
|
||||
|
||||
if(!OperationEval.class.isAssignableFrom(evalClass)) {
|
||||
throw new IllegalArgumentException("Expected OperationEval subclass");
|
||||
}
|
||||
if (!Modifier.isPublic(evalClass.getModifiers())) {
|
||||
throw new RuntimeException("Eval class must be public");
|
||||
}
|
||||
if (Modifier.isAbstract(evalClass.getModifiers())) {
|
||||
throw new RuntimeException("Eval class must not be abstract");
|
||||
}
|
||||
|
||||
Constructor constructor;
|
||||
try {
|
||||
constructor = evalClass.getDeclaredConstructor(OPERATION_CONSTRUCTOR_CLASS_ARRAY);
|
||||
} catch (NoSuchMethodException e) {
|
||||
throw new RuntimeException("Missing constructor");
|
||||
}
|
||||
if (!Modifier.isPublic(constructor.getModifiers())) {
|
||||
throw new RuntimeException("Eval constructor must be public");
|
||||
}
|
||||
m.put(ptgClass, constructor);
|
||||
}
|
||||
|
||||
/**
|
||||
* returns the OperationEval concrete impl instance corresponding
|
||||
* to the supplied operationPtg
|
||||
*/
|
||||
public static OperationEval create(OperationPtg ptg) {
|
||||
if(ptg == null) {
|
||||
throw new IllegalArgumentException("ptg must not be null");
|
||||
}
|
||||
Object result;
|
||||
|
||||
Class ptgClass = ptg.getClass();
|
||||
|
||||
result = _instancesByPtgClass.get(ptgClass);
|
||||
if (result != null) {
|
||||
return (OperationEval) result;
|
||||
}
|
||||
|
||||
|
||||
Constructor constructor = (Constructor) _constructorsByPtgClass.get(ptgClass);
|
||||
if(constructor == null) {
|
||||
if(ptgClass == ExpPtg.class) {
|
||||
// ExpPtg is used for array formulas and shared formulas.
|
||||
// it is currently unsupported, and may not even get implemented here
|
||||
throw new RuntimeException("ExpPtg currently not supported");
|
||||
}
|
||||
throw new RuntimeException("Unexpected operation ptg class (" + ptgClass.getName() + ")");
|
||||
}
|
||||
|
||||
Object[] initargs = { ptg };
|
||||
try {
|
||||
result = constructor.newInstance(initargs);
|
||||
} catch (IllegalArgumentException e) {
|
||||
throw new RuntimeException(e);
|
||||
} catch (InstantiationException e) {
|
||||
throw new RuntimeException(e);
|
||||
} catch (IllegalAccessException e) {
|
||||
throw new RuntimeException(e);
|
||||
} catch (InvocationTargetException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
return (OperationEval) result;
|
||||
}
|
||||
}
|
95
src/java/org/apache/poi/ss/usermodel/EvaluationCache.java
Normal file
95
src/java/org/apache/poi/ss/usermodel/EvaluationCache.java
Normal file
@ -0,0 +1,95 @@
|
||||
/* ====================================================================
|
||||
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.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.poi.hssf.record.formula.eval.ValueEval;
|
||||
|
||||
/**
|
||||
* Performance optimisation for {@link HSSFFormulaEvaluator}. This class stores previously
|
||||
* calculated values of already visited cells, to avoid unnecessary re-calculation when the
|
||||
* same cells are referenced multiple times
|
||||
*
|
||||
*
|
||||
* @author Josh Micich
|
||||
*/
|
||||
final class EvaluationCache {
|
||||
private static final class Key {
|
||||
|
||||
private final int _sheetIndex;
|
||||
private final int _srcRowNum;
|
||||
private final int _srcColNum;
|
||||
private final int _hashCode;
|
||||
|
||||
public Key(int sheetIndex, int srcRowNum, int srcColNum) {
|
||||
_sheetIndex = sheetIndex;
|
||||
_srcRowNum = srcRowNum;
|
||||
_srcColNum = srcColNum;
|
||||
_hashCode = sheetIndex + srcRowNum + srcColNum;
|
||||
}
|
||||
|
||||
public int hashCode() {
|
||||
return _hashCode;
|
||||
}
|
||||
|
||||
public boolean equals(Object obj) {
|
||||
Key other = (Key) obj;
|
||||
if (_hashCode != other._hashCode) {
|
||||
return false;
|
||||
}
|
||||
if (_sheetIndex != other._sheetIndex) {
|
||||
return false;
|
||||
}
|
||||
if (_srcRowNum != other._srcRowNum) {
|
||||
return false;
|
||||
}
|
||||
if (_srcColNum != other._srcColNum) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
private final Map _valuesByKey;
|
||||
|
||||
/* package */EvaluationCache() {
|
||||
_valuesByKey = new HashMap();
|
||||
}
|
||||
|
||||
public ValueEval getValue(int sheetIndex, int srcRowNum, int srcColNum) {
|
||||
Key key = new Key(sheetIndex, srcRowNum, srcColNum);
|
||||
return (ValueEval) _valuesByKey.get(key);
|
||||
}
|
||||
|
||||
public void setValue(int sheetIndex, int srcRowNum, int srcColNum, ValueEval value) {
|
||||
Key key = new Key(sheetIndex, srcRowNum, srcColNum);
|
||||
if (_valuesByKey.containsKey(key)) {
|
||||
throw new RuntimeException("Already have cached value for this cell");
|
||||
}
|
||||
_valuesByKey.put(key, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Should be called whenever there are changes to input cells in the evaluated workbook.
|
||||
*/
|
||||
public void clear() {
|
||||
_valuesByKey.clear();
|
||||
}
|
||||
}
|
@ -20,7 +20,11 @@ package org.apache.poi.ss.usermodel;
|
||||
import java.util.Iterator;
|
||||
import java.util.Stack;
|
||||
|
||||
import org.apache.poi.ss.util.AreaReference;
|
||||
import org.apache.poi.ss.util.CellReference;
|
||||
|
||||
import org.apache.poi.hssf.model.FormulaParser;
|
||||
import org.apache.poi.hssf.record.NameRecord;
|
||||
import org.apache.poi.hssf.record.formula.Area3DPtg;
|
||||
import org.apache.poi.hssf.record.formula.AreaPtg;
|
||||
import org.apache.poi.hssf.record.formula.BoolPtg;
|
||||
@ -56,17 +60,64 @@ import org.apache.poi.hssf.record.formula.eval.StringEval;
|
||||
import org.apache.poi.hssf.record.formula.eval.ValueEval;
|
||||
|
||||
/**
|
||||
* Evaluates formula cells.<p/>
|
||||
*
|
||||
* For performance reasons, this class keeps a cache of all previously calculated intermediate
|
||||
* cell values. Be sure to call {@link #clearCache()} if any workbook cells are changed between
|
||||
* calls to evaluate~ methods on this class.
|
||||
*
|
||||
* @author Amol S. Deshmukh < amolweb at ya hoo dot com >
|
||||
*
|
||||
* @author Josh Micich
|
||||
*/
|
||||
public class FormulaEvaluator {
|
||||
/**
|
||||
* used to track the number of evaluations
|
||||
*/
|
||||
private static final class Counter {
|
||||
public int value;
|
||||
public Counter() {
|
||||
value = 0;
|
||||
}
|
||||
}
|
||||
|
||||
protected Sheet _sheet;
|
||||
protected Workbook _workbook;
|
||||
private final EvaluationCache _cache;
|
||||
|
||||
private Counter _evaluationCounter;
|
||||
|
||||
|
||||
public FormulaEvaluator(Sheet sheet, Workbook workbook) {
|
||||
this(sheet, workbook, new EvaluationCache(), new Counter());
|
||||
}
|
||||
|
||||
private FormulaEvaluator(Sheet sheet, Workbook workbook, EvaluationCache cache, Counter evaluationCounter) {
|
||||
_sheet = sheet;
|
||||
_workbook = workbook;
|
||||
_cache = cache;
|
||||
_evaluationCounter = evaluationCounter;
|
||||
}
|
||||
|
||||
/**
|
||||
* for debug use. Used in toString methods
|
||||
*/
|
||||
public String getSheetName(Sheet sheet) {
|
||||
return _workbook.getSheetName(_workbook.getSheetIndex(sheet));
|
||||
}
|
||||
/**
|
||||
* for debug/test use
|
||||
*/
|
||||
public int getEvaluationCount() {
|
||||
return _evaluationCounter.value;
|
||||
}
|
||||
|
||||
private static boolean isDebugLogEnabled() {
|
||||
return false;
|
||||
}
|
||||
private static void logDebug(String s) {
|
||||
if (isDebugLogEnabled()) {
|
||||
System.out.println(s);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -75,6 +126,18 @@ public class FormulaEvaluator {
|
||||
*/
|
||||
public void setCurrentRow(Row row) {
|
||||
// do nothing
|
||||
if (false) {
|
||||
row.getClass(); // suppress unused parameter compiler warning
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Should be called whenever there are changes to input cells in the evaluated workbook.
|
||||
* Failure to call this method after changing cell values will cause incorrect behaviour
|
||||
* of the evaluate~ methods of this class
|
||||
*/
|
||||
public void clearCache() {
|
||||
_cache.clear();
|
||||
}
|
||||
|
||||
|
||||
@ -102,7 +165,7 @@ public class FormulaEvaluator {
|
||||
retval.setErrorValue(cell.getErrorCellValue());
|
||||
break;
|
||||
case Cell.CELL_TYPE_FORMULA:
|
||||
retval = getCellValueForEval(internalEvaluate(cell, _sheet, _workbook), _workbook.getCreationHelper());
|
||||
retval = getCellValueForEval(internalEvaluate(cell, _sheet), _workbook.getCreationHelper());
|
||||
break;
|
||||
case Cell.CELL_TYPE_NUMERIC:
|
||||
retval = new CellValue(Cell.CELL_TYPE_NUMERIC, _workbook.getCreationHelper());
|
||||
@ -140,7 +203,7 @@ public class FormulaEvaluator {
|
||||
if (cell != null) {
|
||||
switch (cell.getCellType()) {
|
||||
case Cell.CELL_TYPE_FORMULA:
|
||||
CellValue cv = getCellValueForEval(internalEvaluate(cell, _sheet, _workbook), _workbook.getCreationHelper());
|
||||
CellValue cv = getCellValueForEval(internalEvaluate(cell, _sheet), _workbook.getCreationHelper());
|
||||
switch (cv.getCellType()) {
|
||||
case Cell.CELL_TYPE_BOOLEAN:
|
||||
cell.setCellValue(cv.getBooleanValue());
|
||||
@ -185,7 +248,7 @@ public class FormulaEvaluator {
|
||||
if (cell != null) {
|
||||
switch (cell.getCellType()) {
|
||||
case Cell.CELL_TYPE_FORMULA:
|
||||
CellValue cv = getCellValueForEval(internalEvaluate(cell, _sheet, _workbook), _workbook.getCreationHelper());
|
||||
CellValue cv = getCellValueForEval(internalEvaluate(cell, _sheet), _workbook.getCreationHelper());
|
||||
switch (cv.getCellType()) {
|
||||
case Cell.CELL_TYPE_BOOLEAN:
|
||||
cell.setCellType(Cell.CELL_TYPE_BOOLEAN);
|
||||
@ -283,26 +346,40 @@ public class FormulaEvaluator {
|
||||
* 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) {
|
||||
private ValueEval internalEvaluate(Cell srcCell, Sheet sheet) {
|
||||
int srcRowNum = srcCell.getRowIndex();
|
||||
short srcColNum = srcCell.getCellNum();
|
||||
int srcColNum = srcCell.getCellNum();
|
||||
|
||||
ValueEval result;
|
||||
|
||||
int sheetIndex = _workbook.getSheetIndex(sheet);
|
||||
result = _cache.getValue(sheetIndex, srcRowNum, srcColNum);
|
||||
if (result != null) {
|
||||
return result;
|
||||
}
|
||||
_evaluationCounter.value++;
|
||||
|
||||
EvaluationCycleDetector tracker = EvaluationCycleDetectorManager.getTracker();
|
||||
|
||||
if(!tracker.startEvaluate(workbook, sheet, srcRowNum, srcColNum)) {
|
||||
if(!tracker.startEvaluate(_workbook, sheet, srcRowNum, srcColNum)) {
|
||||
return ErrorEval.CIRCULAR_REF_ERROR;
|
||||
}
|
||||
try {
|
||||
return evaluateCell(workbook, sheet, srcRowNum, srcColNum, srcCell.getCellFormula());
|
||||
result = evaluateCell(srcRowNum, (short)srcColNum, srcCell.getCellFormula());
|
||||
} finally {
|
||||
tracker.endEvaluate(workbook, sheet, srcRowNum, srcColNum);
|
||||
tracker.endEvaluate(_workbook, sheet, srcRowNum, srcColNum);
|
||||
_cache.setValue(sheetIndex, srcRowNum, srcColNum, result);
|
||||
}
|
||||
if (isDebugLogEnabled()) {
|
||||
String sheetName = _workbook.getSheetName(sheetIndex);
|
||||
CellReference cr = new CellReference(srcRowNum, srcColNum);
|
||||
logDebug("Evaluated " + sheetName + "!" + cr.formatAsString() + " to " + result.toString());
|
||||
}
|
||||
return result;
|
||||
}
|
||||
private static ValueEval evaluateCell(Workbook workbook, Sheet sheet,
|
||||
int srcRowNum, short srcColNum, String cellFormulaText) {
|
||||
private ValueEval evaluateCell(int srcRowNum, short srcColNum, String cellFormulaText) {
|
||||
|
||||
Ptg[] ptgs = FormulaParser.parse(cellFormulaText, workbook);
|
||||
Ptg[] ptgs = FormulaParser.parse(cellFormulaText, _workbook);
|
||||
|
||||
Stack stack = new Stack();
|
||||
for (int i = 0, iSize = ptgs.length; i < iSize; i++) {
|
||||
@ -314,19 +391,10 @@ public class FormulaEvaluator {
|
||||
continue;
|
||||
}
|
||||
if (ptg instanceof MemErrPtg) { continue; }
|
||||
if (ptg instanceof MissingArgPtg) { continue; }
|
||||
if (ptg instanceof NamePtg) {
|
||||
// named ranges, macro functions
|
||||
NamePtg namePtg = (NamePtg) ptg;
|
||||
stack.push(new NameEval(namePtg.getIndex()));
|
||||
continue;
|
||||
if (ptg instanceof MissingArgPtg) {
|
||||
// TODO - might need to push BlankEval or MissingArgEval
|
||||
continue;
|
||||
}
|
||||
if (ptg instanceof NameXPtg) {
|
||||
NameXPtg nameXPtg = (NameXPtg) ptg;
|
||||
stack.push(new NameXEval(nameXPtg.getSheetRefIndex(), nameXPtg.getNameIndex()));
|
||||
continue;
|
||||
}
|
||||
if (ptg instanceof UnknownPtg) { continue; }
|
||||
Eval opResult;
|
||||
if (ptg instanceof OperationPtg) {
|
||||
OperationPtg optg = (OperationPtg) ptg;
|
||||
@ -343,10 +411,15 @@ public class FormulaEvaluator {
|
||||
Eval p = (Eval) stack.pop();
|
||||
ops[j] = p;
|
||||
}
|
||||
opResult = invokeOperation(operation, ops, srcRowNum, srcColNum, workbook, sheet);
|
||||
logDebug("invoke " + operation + " (nAgs=" + numops + ")");
|
||||
opResult = invokeOperation(operation, ops, srcRowNum, srcColNum, _workbook, _sheet);
|
||||
} else {
|
||||
opResult = getEvalForPtg(ptg, sheet, workbook);
|
||||
opResult = getEvalForPtg(ptg, _sheet);
|
||||
}
|
||||
if (opResult == null) {
|
||||
throw new RuntimeException("Evaluation result must not be null");
|
||||
}
|
||||
logDebug("push " + opResult);
|
||||
stack.push(opResult);
|
||||
}
|
||||
|
||||
@ -403,28 +476,63 @@ public class FormulaEvaluator {
|
||||
return operation.evaluate(ops, srcRowNum, srcColNum);
|
||||
}
|
||||
|
||||
private Sheet getOtherSheet(int externSheetIndex) {
|
||||
return _workbook.getSheetAt(_workbook.getSheetIndexFromExternSheetIndex(externSheetIndex));
|
||||
}
|
||||
private FormulaEvaluator createEvaluatorForAnotherSheet(Sheet sheet) {
|
||||
return new FormulaEvaluator(sheet, _workbook, _cache, _evaluationCounter);
|
||||
}
|
||||
|
||||
/**
|
||||
* returns an appropriate Eval impl instance for the Ptg. The Ptg must be
|
||||
* one of: Area3DPtg, AreaPtg, ReferencePtg, Ref3DPtg, IntPtg, NumberPtg,
|
||||
* StringPtg, BoolPtg <br/>special Note: OperationPtg subtypes cannot be
|
||||
* passed here!
|
||||
*/
|
||||
private static Eval getEvalForPtg(Ptg ptg, Sheet sheet, Workbook workbook) {
|
||||
private Eval getEvalForPtg(Ptg ptg, Sheet sheet) {
|
||||
if (ptg instanceof NamePtg) {
|
||||
// named ranges, macro functions
|
||||
NamePtg namePtg = (NamePtg) ptg;
|
||||
int numberOfNames = _workbook.getNumberOfNames();
|
||||
int nameIndex = namePtg.getIndex();
|
||||
if(nameIndex < 0 || nameIndex >= numberOfNames) {
|
||||
throw new RuntimeException("Bad name index (" + nameIndex
|
||||
+ "). Allowed range is (0.." + (numberOfNames-1) + ")");
|
||||
}
|
||||
if(_workbook instanceof org.apache.poi.hssf.usermodel.HSSFWorkbook) {
|
||||
org.apache.poi.hssf.usermodel.HSSFWorkbook hssfWb =
|
||||
(org.apache.poi.hssf.usermodel.HSSFWorkbook)_workbook;
|
||||
NameRecord nameRecord = hssfWb.getNameRecord(nameIndex);
|
||||
if (nameRecord.isFunctionName()) {
|
||||
return new NameEval(nameRecord.getNameText());
|
||||
}
|
||||
if (nameRecord.hasFormula()) {
|
||||
return evaluateNameFormula(nameRecord.getNameDefinition(), sheet);
|
||||
}
|
||||
throw new RuntimeException("Don't know how to evalate name '" + nameRecord.getNameText() + "'");
|
||||
} else {
|
||||
throw new RuntimeException("Don't know how to evaluate name records for XSSF");
|
||||
}
|
||||
}
|
||||
if (ptg instanceof NameXPtg) {
|
||||
NameXPtg nameXPtg = (NameXPtg) ptg;
|
||||
return new NameXEval(nameXPtg.getSheetRefIndex(), nameXPtg.getNameIndex());
|
||||
}
|
||||
if (ptg instanceof RefPtg) {
|
||||
return new LazyRefEval(((RefPtg) ptg), sheet, workbook);
|
||||
return new LazyRefEval(((RefPtg) ptg), sheet, this);
|
||||
}
|
||||
if (ptg instanceof Ref3DPtg) {
|
||||
Ref3DPtg refPtg = (Ref3DPtg) ptg;
|
||||
Sheet xsheet = workbook.getSheetAt(workbook.getSheetIndexFromExternSheetIndex(refPtg.getExternSheetIndex()));
|
||||
return new LazyRefEval(refPtg, xsheet, workbook);
|
||||
Sheet xsheet = getOtherSheet(refPtg.getExternSheetIndex());
|
||||
return new LazyRefEval(refPtg, xsheet, createEvaluatorForAnotherSheet(xsheet));
|
||||
}
|
||||
if (ptg instanceof AreaPtg) {
|
||||
return new LazyAreaEval(((AreaPtg) ptg), sheet, workbook);
|
||||
return new LazyAreaEval(((AreaPtg) ptg), sheet, this);
|
||||
}
|
||||
if (ptg instanceof Area3DPtg) {
|
||||
Area3DPtg a3dp = (Area3DPtg) ptg;
|
||||
Sheet xsheet = workbook.getSheetAt(workbook.getSheetIndexFromExternSheetIndex(a3dp.getExternSheetIndex()));
|
||||
return new LazyAreaEval(a3dp, xsheet, workbook);
|
||||
Sheet xsheet = getOtherSheet(a3dp.getExternSheetIndex());
|
||||
return new LazyAreaEval(a3dp, xsheet, createEvaluatorForAnotherSheet(xsheet));
|
||||
}
|
||||
|
||||
if (ptg instanceof IntPtg) {
|
||||
@ -442,8 +550,19 @@ public class FormulaEvaluator {
|
||||
if (ptg instanceof ErrPtg) {
|
||||
return ErrorEval.valueOf(((ErrPtg) ptg).getErrorCode());
|
||||
}
|
||||
if (ptg instanceof UnknownPtg) {
|
||||
// TODO - remove UnknownPtg
|
||||
throw new RuntimeException("UnknownPtg not allowed");
|
||||
}
|
||||
throw new RuntimeException("Unexpected ptg class (" + ptg.getClass().getName() + ")");
|
||||
}
|
||||
private Eval evaluateNameFormula(Ptg[] ptgs, Sheet sheet) {
|
||||
if (ptgs.length > 1) {
|
||||
throw new RuntimeException("Complex name formulas not supported yet");
|
||||
}
|
||||
return getEvalForPtg(ptgs[0], sheet);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
@ -453,7 +572,7 @@ public class FormulaEvaluator {
|
||||
* @param sheet
|
||||
* @param workbook
|
||||
*/
|
||||
public static ValueEval getEvalForCell(Cell cell, Sheet sheet, Workbook workbook) {
|
||||
public ValueEval getEvalForCell(Cell cell, Sheet sheet) {
|
||||
|
||||
if (cell == null) {
|
||||
return BlankEval.INSTANCE;
|
||||
@ -464,7 +583,7 @@ public class FormulaEvaluator {
|
||||
case Cell.CELL_TYPE_STRING:
|
||||
return new StringEval(cell.getRichStringCellValue().getString());
|
||||
case Cell.CELL_TYPE_FORMULA:
|
||||
return internalEvaluate(cell, sheet, workbook);
|
||||
return internalEvaluate(cell, sheet);
|
||||
case Cell.CELL_TYPE_BOOLEAN:
|
||||
return BoolEval.valueOf(cell.getBooleanCellValue());
|
||||
case Cell.CELL_TYPE_BLANK:
|
||||
|
@ -69,8 +69,9 @@ import org.apache.poi.hssf.record.formula.eval.UnaryPlusEval;
|
||||
*/
|
||||
final class OperationEvaluatorFactory {
|
||||
private static final Class[] OPERATION_CONSTRUCTOR_CLASS_ARRAY = new Class[] { Ptg.class };
|
||||
|
||||
// TODO - use singleton instances directly instead of reflection
|
||||
private static final Map _constructorsByPtgClass = initialiseConstructorsMap();
|
||||
private static final Map _instancesByPtgClass = initialiseInstancesMap();
|
||||
|
||||
private OperationEvaluatorFactory() {
|
||||
// no instances of this class
|
||||
@ -78,32 +79,44 @@ final class OperationEvaluatorFactory {
|
||||
|
||||
private static Map initialiseConstructorsMap() {
|
||||
Map m = new HashMap(32);
|
||||
add(m, AddPtg.class, AddEval.class);
|
||||
add(m, ConcatPtg.class, ConcatEval.class);
|
||||
add(m, DividePtg.class, DivideEval.class);
|
||||
add(m, EqualPtg.class, EqualEval.class);
|
||||
add(m, FuncPtg.class, FuncVarEval.class);
|
||||
add(m, FuncVarPtg.class, FuncVarEval.class);
|
||||
add(m, GreaterEqualPtg.class, GreaterEqualEval.class);
|
||||
add(m, GreaterThanPtg.class, GreaterThanEval.class);
|
||||
add(m, LessEqualPtg.class, LessEqualEval.class);
|
||||
add(m, LessThanPtg.class, LessThanEval.class);
|
||||
add(m, MultiplyPtg.class, MultiplyEval.class);
|
||||
add(m, NotEqualPtg.class, NotEqualEval.class);
|
||||
add(m, PercentPtg.class, PercentEval.class);
|
||||
add(m, PowerPtg.class, PowerEval.class);
|
||||
add(m, SubtractPtg.class, SubtractEval.class);
|
||||
add(m, UnaryMinusPtg.class, UnaryMinusEval.class);
|
||||
add(m, UnaryPlusPtg.class, UnaryPlusEval.class);
|
||||
return m;
|
||||
}
|
||||
private static Map initialiseInstancesMap() {
|
||||
Map m = new HashMap(32);
|
||||
add(m, EqualPtg.class, EqualEval.instance);
|
||||
add(m, GreaterEqualPtg.class, GreaterEqualEval.instance);
|
||||
add(m, GreaterThanPtg.class, GreaterThanEval.instance);
|
||||
add(m, LessEqualPtg.class, LessEqualEval.instance);
|
||||
add(m, LessThanPtg.class, LessThanEval.instance);
|
||||
add(m, NotEqualPtg.class, NotEqualEval.instance);
|
||||
|
||||
add(m, AddPtg.class, AddEval.instance);
|
||||
add(m, DividePtg.class, DivideEval.instance);
|
||||
add(m, MultiplyPtg.class, MultiplyEval.instance);
|
||||
add(m, PercentPtg.class, PercentEval.instance);
|
||||
add(m, PowerPtg.class, PowerEval.instance);
|
||||
add(m, SubtractPtg.class, SubtractEval.instance);
|
||||
add(m, UnaryMinusPtg.class, UnaryMinusEval.instance);
|
||||
add(m, UnaryPlusPtg.class, UnaryPlusEval.instance);
|
||||
return m;
|
||||
}
|
||||
|
||||
private static void add(Map m, Class ptgClass, OperationEval evalInstance) {
|
||||
if(!Ptg.class.isAssignableFrom(ptgClass)) {
|
||||
throw new IllegalArgumentException("Expected Ptg subclass");
|
||||
}
|
||||
m.put(ptgClass, evalInstance);
|
||||
}
|
||||
|
||||
private static void add(Map m, Class ptgClass, Class evalClass) {
|
||||
|
||||
// perform some validation now, to keep later exception handlers simple
|
||||
if(!Ptg.class.isAssignableFrom(ptgClass)) {
|
||||
throw new IllegalArgumentException("Expected Ptg subclass");
|
||||
}
|
||||
|
||||
if(!OperationEval.class.isAssignableFrom(evalClass)) {
|
||||
throw new IllegalArgumentException("Expected OperationEval subclass");
|
||||
}
|
||||
@ -125,7 +138,7 @@ final class OperationEvaluatorFactory {
|
||||
}
|
||||
m.put(ptgClass, constructor);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* returns the OperationEval concrete impl instance corresponding
|
||||
* to the supplied operationPtg
|
||||
@ -134,9 +147,16 @@ final class OperationEvaluatorFactory {
|
||||
if(ptg == null) {
|
||||
throw new IllegalArgumentException("ptg must not be null");
|
||||
}
|
||||
Object result;
|
||||
|
||||
Class ptgClass = ptg.getClass();
|
||||
|
||||
result = _instancesByPtgClass.get(ptgClass);
|
||||
if (result != null) {
|
||||
return (OperationEval) result;
|
||||
}
|
||||
|
||||
|
||||
Constructor constructor = (Constructor) _constructorsByPtgClass.get(ptgClass);
|
||||
if(constructor == null) {
|
||||
if(ptgClass == ExpPtg.class) {
|
||||
@ -147,7 +167,6 @@ final class OperationEvaluatorFactory {
|
||||
throw new RuntimeException("Unexpected operation ptg class (" + ptgClass.getName() + ")");
|
||||
}
|
||||
|
||||
Object result;
|
||||
Object[] initargs = { ptg };
|
||||
try {
|
||||
result = constructor.newInstance(initargs);
|
||||
|
@ -46,29 +46,59 @@ public class AreaReference {
|
||||
}
|
||||
|
||||
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 {
|
||||
String part0 = parts[0];
|
||||
if (parts.length == 1) {
|
||||
// TODO - probably shouldn't initialize area ref when text is really a cell ref
|
||||
// Need to fix some named range stuff to get rid of this
|
||||
_firstCell = new CellReference(part0);
|
||||
|
||||
_lastCell = _firstCell;
|
||||
_isSingleCell = true;
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (parts.length != 2) {
|
||||
throw new IllegalArgumentException("Bad area ref '" + reference + "'");
|
||||
}
|
||||
|
||||
String part1 = parts[1];
|
||||
if (isPlainColumn(part0)) {
|
||||
if (!isPlainColumn(part1)) {
|
||||
throw new RuntimeException("Bad area ref '" + reference + "'");
|
||||
}
|
||||
// Special handling for whole-column references
|
||||
// Represented internally as x$1 to x$65536
|
||||
// which is the maximum range of rows
|
||||
|
||||
boolean firstIsAbs = CellReference.isPartAbsolute(part0);
|
||||
boolean lastIsAbs = CellReference.isPartAbsolute(part1);
|
||||
|
||||
int col0 = CellReference.convertColStringToIndex(part0);
|
||||
int col1 = CellReference.convertColStringToIndex(part1);
|
||||
|
||||
_firstCell = new CellReference(0, col0, true, firstIsAbs);
|
||||
_lastCell = new CellReference(0xFFFF, col1, true, lastIsAbs);
|
||||
_isSingleCell = false;
|
||||
// TODO - whole row refs
|
||||
} else {
|
||||
_firstCell = new CellReference(part0);
|
||||
_lastCell = new CellReference(part1);
|
||||
_isSingleCell = part0.equals(part1);
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isPlainColumn(String refPart) {
|
||||
for(int i=refPart.length()-1; i>=0; i--) {
|
||||
int ch = refPart.charAt(i);
|
||||
if (ch == '$' && i==0) {
|
||||
continue;
|
||||
}
|
||||
if (ch < 'A' || ch > 'Z') {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an area ref from a pair of Cell References.
|
||||
*/
|
||||
|
@ -80,7 +80,7 @@ public class CellReference {
|
||||
if (_isColAbs) {
|
||||
colRef=colRef.substring(1);
|
||||
}
|
||||
_colIndex = convertColStringToNum(colRef);
|
||||
_colIndex = convertColStringToIndex(colRef);
|
||||
|
||||
String rowRef=parts[2];
|
||||
if (rowRef.length() < 1) {
|
||||
@ -94,7 +94,7 @@ public class CellReference {
|
||||
}
|
||||
|
||||
public CellReference(int pRow, int pCol) {
|
||||
this(pRow, pCol, false, false);
|
||||
this(pRow, pCol & 0xFFFF, false, false);
|
||||
}
|
||||
public CellReference(int pRow, short pCol) {
|
||||
this(pRow, (int)pCol, false, false);
|
||||
@ -130,18 +130,31 @@ public class CellReference {
|
||||
public String getSheetName(){
|
||||
return _sheetName;
|
||||
}
|
||||
|
||||
|
||||
public static boolean isPartAbsolute(String part) {
|
||||
return part.charAt(0) == ABSOLUTE_REFERENCE_MARKER;
|
||||
}
|
||||
|
||||
/**
|
||||
* takes in a column reference portion of a CellRef and converts it from
|
||||
* ALPHA-26 number format to 0-based base 10.
|
||||
* 'A' -> 0
|
||||
* 'Z' -> 25
|
||||
* 'AA' -> 26
|
||||
* 'IV' -> 255
|
||||
* @return zero based column index
|
||||
*/
|
||||
private int convertColStringToNum(String ref) {
|
||||
int lastIx = ref.length()-1;
|
||||
int retval=0;
|
||||
int pos = 0;
|
||||
|
||||
for (int k = lastIx; k > -1; k--) {
|
||||
protected static int convertColStringToIndex(String ref) {
|
||||
int pos = 0;
|
||||
int retval=0;
|
||||
for (int k = ref.length()-1; k >= 0; k--) {
|
||||
char thechar = ref.charAt(k);
|
||||
if (thechar == ABSOLUTE_REFERENCE_MARKER) {
|
||||
if (k != 0) {
|
||||
throw new IllegalArgumentException("Bad col ref format '" + ref + "'");
|
||||
}
|
||||
break;
|
||||
}
|
||||
// Character.getNumericValue() returns the values
|
||||
// 10-35 for the letter A-Z
|
||||
int shift = (int)Math.pow(26, pos);
|
||||
|
@ -71,27 +71,44 @@ public class Document extends PositionDependentRecordContainer
|
||||
* This will normally return an array of size 2 or 3
|
||||
*/
|
||||
public SlideListWithText[] getSlideListWithTexts() { return slwts; }
|
||||
/**
|
||||
|
||||
/**
|
||||
* Returns the SlideListWithText that deals with the
|
||||
* Master Slides
|
||||
*/
|
||||
public SlideListWithText getMasterSlideListWithText() {
|
||||
if(slwts.length > 0) { return slwts[0]; }
|
||||
return null; }
|
||||
for (int i = 0; i < slwts.length; i++) {
|
||||
if(slwts[i].getInstance() == SlideListWithText.MASTER) {
|
||||
return slwts[i];
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the SlideListWithText that deals with the
|
||||
* Slides, or null if there isn't one
|
||||
*/
|
||||
public SlideListWithText getSlideSlideListWithText() {
|
||||
if(slwts.length > 1) { return slwts[1]; }
|
||||
return null; }
|
||||
public SlideListWithText getSlideSlideListWithText() {
|
||||
for (int i = 0; i < slwts.length; i++) {
|
||||
if(slwts[i].getInstance() == SlideListWithText.SLIDES) {
|
||||
return slwts[i];
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
/**
|
||||
* Returns the SlideListWithText that deals with the
|
||||
* notes, or null if there isn't one
|
||||
*/
|
||||
public SlideListWithText getNotesSlideListWithText() {
|
||||
if(slwts.length > 2) { return slwts[2]; }
|
||||
return null; }
|
||||
for (int i = 0; i < slwts.length; i++) {
|
||||
if(slwts[i].getInstance() == SlideListWithText.NOTES) {
|
||||
return slwts[i];
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
|
@ -243,8 +243,16 @@ public abstract class RecordContainer extends Record
|
||||
moveChildRecords(oldLoc, newLoc, number);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Set child records.
|
||||
*
|
||||
* @param records the new child records
|
||||
*/
|
||||
public void setChildRecord(Record[] records) {
|
||||
this._children = records;
|
||||
}
|
||||
|
||||
/* ===============================================================
|
||||
* External Serialisation Methods
|
||||
* ===============================================================
|
||||
|
@ -50,7 +50,24 @@ import java.util.Vector;
|
||||
// For now, pretend to be an atom
|
||||
public class SlideListWithText extends RecordContainer
|
||||
{
|
||||
private byte[] _header;
|
||||
|
||||
/**
|
||||
* Instance filed of the record header indicates that this SlideListWithText stores
|
||||
* references to slides
|
||||
*/
|
||||
public static final int SLIDES = 0;
|
||||
/**
|
||||
* Instance filed of the record header indicates that this SlideListWithText stores
|
||||
* references to master slides
|
||||
*/
|
||||
public static final int MASTER = 1;
|
||||
/**
|
||||
* Instance filed of the record header indicates that this SlideListWithText stores
|
||||
* references to notes
|
||||
*/
|
||||
public static final int NOTES = 2;
|
||||
|
||||
private byte[] _header;
|
||||
private static long _type = 4080;
|
||||
|
||||
private SlideAtomsSet[] slideAtomsSets;
|
||||
@ -123,9 +140,9 @@ public class SlideListWithText extends RecordContainer
|
||||
public void addSlidePersistAtom(SlidePersistAtom spa) {
|
||||
// Add the new SlidePersistAtom at the end
|
||||
appendChildRecord(spa);
|
||||
|
||||
|
||||
SlideAtomsSet newSAS = new SlideAtomsSet(spa, new Record[0]);
|
||||
|
||||
|
||||
// Update our SlideAtomsSets with this
|
||||
SlideAtomsSet[] sas = new SlideAtomsSet[slideAtomsSets.length+1];
|
||||
System.arraycopy(slideAtomsSets, 0, sas, 0, slideAtomsSets.length);
|
||||
@ -133,7 +150,15 @@ public class SlideListWithText extends RecordContainer
|
||||
slideAtomsSets = sas;
|
||||
}
|
||||
|
||||
/**
|
||||
public int getInstance(){
|
||||
return LittleEndian.getShort(_header, 0) >> 4;
|
||||
}
|
||||
|
||||
public void setInstance(int inst){
|
||||
LittleEndian.putShort(_header, (short)((inst << 4) | 0xF));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get access to the SlideAtomsSets of the children of this record
|
||||
*/
|
||||
public SlideAtomsSet[] getSlideAtomsSets() { return slideAtomsSets; }
|
||||
@ -152,35 +177,6 @@ public class SlideListWithText extends RecordContainer
|
||||
}
|
||||
|
||||
/**
|
||||
* Shifts a SlideAtomsSet to a new position.
|
||||
* Works by shifting the child records about, then updating
|
||||
* the SlideAtomSets array
|
||||
* @param toMove The SlideAtomsSet to move
|
||||
* @param newPosition The new (0 based) position for the SlideAtomsSet
|
||||
*/
|
||||
public void repositionSlideAtomsSet(SlideAtomsSet toMove, int newPosition) {
|
||||
// Ensure it's one of ours
|
||||
int curPos = -1;
|
||||
for(int i=0; i<slideAtomsSets.length; i++) {
|
||||
if(slideAtomsSets[i] == toMove) { curPos = i; }
|
||||
}
|
||||
if(curPos == -1) {
|
||||
throw new IllegalArgumentException("The supplied SlideAtomsSet didn't belong to this SlideListWithText");
|
||||
}
|
||||
|
||||
// Ensure the newPosision is valid
|
||||
if(newPosition < 0 || newPosition >= slideAtomsSets.length) {
|
||||
throw new IllegalArgumentException("The new position must be between 0, and the number of SlideAtomsSets");
|
||||
}
|
||||
|
||||
// Build the new records list
|
||||
moveChildrenBefore(toMove.getSlidePersistAtom(), toMove.slideRecords.length, slideAtomsSets[newPosition].getSlidePersistAtom());
|
||||
|
||||
// Build the new SlideAtomsSets list
|
||||
ArrayUtil.arrayMoveWithin(slideAtomsSets, curPos, newPosition, 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Inner class to wrap up a matching set of records that hold the
|
||||
* text for a given sheet. Contains the leading SlidePersistAtom,
|
||||
* and all of the records until the next SlidePersistAtom. This
|
||||
|
@ -536,32 +536,37 @@ public final class SlideShow {
|
||||
|
||||
/**
|
||||
* Re-orders a slide, to a new position.
|
||||
* @param oldSlideNumer The old slide number (1 based)
|
||||
* @param oldSlideNumber The old slide number (1 based)
|
||||
* @param newSlideNumber The new slide number (1 based)
|
||||
*/
|
||||
public void reorderSlide(int oldSlideNumer, int newSlideNumber) {
|
||||
public void reorderSlide(int oldSlideNumber, int newSlideNumber) {
|
||||
// Ensure these numbers are valid
|
||||
if(oldSlideNumer < 1 || newSlideNumber < 1) {
|
||||
if(oldSlideNumber < 1 || newSlideNumber < 1) {
|
||||
throw new IllegalArgumentException("Old and new slide numbers must be greater than 0");
|
||||
}
|
||||
if(oldSlideNumer > _slides.length || newSlideNumber > _slides.length) {
|
||||
if(oldSlideNumber > _slides.length || newSlideNumber > _slides.length) {
|
||||
throw new IllegalArgumentException("Old and new slide numbers must not exceed the number of slides (" + _slides.length + ")");
|
||||
}
|
||||
|
||||
// Shift the SlideAtomsSet
|
||||
SlideListWithText slwt = _documentRecord.getSlideSlideListWithText();
|
||||
slwt.repositionSlideAtomsSet(
|
||||
slwt.getSlideAtomsSets()[(oldSlideNumer-1)],
|
||||
(newSlideNumber-1)
|
||||
);
|
||||
|
||||
// Re-order the slides
|
||||
ArrayUtil.arrayMoveWithin(_slides, (oldSlideNumer-1), (newSlideNumber-1), 1);
|
||||
|
||||
// Tell the appropriate slides their new numbers
|
||||
for(int i=0; i<_slides.length; i++) {
|
||||
_slides[i].setSlideNumber( (i+1) );
|
||||
}
|
||||
|
||||
// The order of slides is defined by the order of slide atom sets in the SlideListWithText container.
|
||||
SlideListWithText slwt = _documentRecord.getSlideSlideListWithText();
|
||||
SlideAtomsSet[] sas = slwt.getSlideAtomsSets();
|
||||
|
||||
SlideAtomsSet tmp = sas[oldSlideNumber-1];
|
||||
sas[oldSlideNumber-1] = sas[newSlideNumber-1];
|
||||
sas[newSlideNumber-1] = tmp;
|
||||
|
||||
ArrayList lst = new ArrayList();
|
||||
for (int i = 0; i < sas.length; i++) {
|
||||
lst.add(sas[i].getSlidePersistAtom());
|
||||
Record[] r = sas[i].getSlideRecords();
|
||||
for (int j = 0; j < r.length; j++) {
|
||||
lst.add(r[j]);
|
||||
}
|
||||
_slides[i].setSlideNumber(i+1);
|
||||
}
|
||||
Record[] r = (Record[])lst.toArray(new Record[lst.size()]);
|
||||
slwt.setChildRecord(r);
|
||||
}
|
||||
|
||||
/* ===============================================================
|
||||
@ -585,7 +590,8 @@ public final class SlideShow {
|
||||
if(slist == null) {
|
||||
// Need to add a new one
|
||||
slist = new SlideListWithText();
|
||||
_documentRecord.addSlideListWithText(slist);
|
||||
slist.setInstance(SlideListWithText.SLIDES);
|
||||
_documentRecord.addSlideListWithText(slist);
|
||||
}
|
||||
|
||||
// Grab the SlidePersistAtom with the highest Slide Number.
|
||||
@ -678,11 +684,11 @@ public final class SlideShow {
|
||||
ptr.addSlideLookup(sp.getRefID(), slideOffset);
|
||||
logger.log(POILogger.INFO, "New slide ended up at " + slideOffset);
|
||||
|
||||
// All done and added
|
||||
slide.setMasterSheet(_masters[0]);
|
||||
// All done and added
|
||||
return slide;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Adds a picture to this presentation and returns the associated index.
|
||||
*
|
||||
|
@ -279,18 +279,23 @@ public class TestReOrderingSlides extends TestCase {
|
||||
assertEquals(3, ss_read.getSlides().length);
|
||||
|
||||
// And check it's as expected
|
||||
s1 = ss_read.getSlides()[0];
|
||||
s2 = ss_read.getSlides()[1];
|
||||
s3 = ss_read.getSlides()[2];
|
||||
|
||||
assertEquals(257, s1._getSheetNumber());
|
||||
assertEquals(4, s1._getSheetRefId());
|
||||
Slide _s1 = ss_read.getSlides()[0];
|
||||
Slide _s2 = ss_read.getSlides()[1];
|
||||
Slide _s3 = ss_read.getSlides()[2];
|
||||
|
||||
// 1 --> 3
|
||||
assertEquals(s1._getSheetNumber(), _s3._getSheetNumber());
|
||||
assertEquals(s1._getSheetRefId(), _s3._getSheetRefId());
|
||||
assertEquals(1, s1.getSlideNumber());
|
||||
assertEquals(256, s2._getSheetNumber());
|
||||
assertEquals(3, s2._getSheetRefId());
|
||||
|
||||
// 2nd slide is not updated
|
||||
assertEquals(s2._getSheetNumber(), _s2._getSheetNumber());
|
||||
assertEquals(s2._getSheetRefId(), _s2._getSheetRefId());
|
||||
assertEquals(2, s2.getSlideNumber());
|
||||
assertEquals(258, s3._getSheetNumber());
|
||||
assertEquals(5, s3._getSheetRefId());
|
||||
|
||||
// 3 --> 1
|
||||
assertEquals(s3._getSheetNumber(), _s1._getSheetNumber());
|
||||
assertEquals(s3._getSheetRefId(), _s1._getSheetRefId());
|
||||
assertEquals(3, s3.getSlideNumber());
|
||||
}
|
||||
}
|
||||
|
Binary file not shown.
BIN
src/testcases/org/apache/poi/hssf/data/45720.xls
Executable file
BIN
src/testcases/org/apache/poi/hssf/data/45720.xls
Executable file
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -74,9 +74,18 @@ public final class TestExternalFunctionFormulas extends TestCase {
|
||||
public void testEvaluate() {
|
||||
HSSFWorkbook wb = HSSFTestDataSamples.openSampleWorkbook("externalFunctionExample.xls");
|
||||
HSSFSheet sheet = wb.getSheetAt(0);
|
||||
HSSFCell cell = sheet.getRow(0).getCell(0);
|
||||
HSSFFormulaEvaluator fe = new HSSFFormulaEvaluator(sheet, wb);
|
||||
CellValue evalResult = fe.evaluate(cell);
|
||||
evalResult.toString();
|
||||
confirmCellEval(sheet, 0, 0, fe, "YEARFRAC(B1,C1)", 29.0/90.0);
|
||||
confirmCellEval(sheet, 1, 0, fe, "YEARFRAC(B2,C2)", 0.0);
|
||||
confirmCellEval(sheet, 2, 0, fe, "IF(ISEVEN(3),1.2,1.6)", 1.6);
|
||||
confirmCellEval(sheet, 3, 0, fe, "IF(ISODD(3),1.2,1.6)", 1.2);
|
||||
}
|
||||
|
||||
private static void confirmCellEval(HSSFSheet sheet, int rowIx, int colIx,
|
||||
HSSFFormulaEvaluator fe, String expectedFormula, double expectedResult) {
|
||||
HSSFCell cell = sheet.getRow(rowIx).getCell(colIx);
|
||||
assertEquals(expectedFormula, cell.getCellFormula());
|
||||
CellValue cv = fe.evaluate(cell);
|
||||
assertEquals(expectedResult, cv.getNumberValue(), 0.0);
|
||||
}
|
||||
}
|
||||
|
@ -38,6 +38,7 @@ public final class TestYearFracCalculator extends TestCase {
|
||||
confirm(md(1999, 3, 31), md(1999, 4, 3), 1, 0.008219178);
|
||||
confirm(md(1999, 4, 5), md(1999, 4, 8), 1, 0.008219178);
|
||||
confirm(md(1999, 4, 4), md(1999, 4, 7), 1, 0.008219178);
|
||||
confirm(md(2000, 2, 5), md(2000, 6, 1), 0, 0.322222222);
|
||||
}
|
||||
|
||||
private void confirm(double startDate, double endDate, int basis, double expectedValue) {
|
||||
|
@ -31,6 +31,8 @@ public class AllFormulaEvalTests {
|
||||
TestSuite result = new TestSuite(AllFormulaEvalTests.class.getName());
|
||||
result.addTestSuite(TestAreaEval.class);
|
||||
result.addTestSuite(TestCircularReferences.class);
|
||||
result.addTestSuite(TestDivideEval.class);
|
||||
result.addTestSuite(TestEqualEval.class);
|
||||
result.addTestSuite(TestExternalFunction.class);
|
||||
result.addTestSuite(TestFormulaBugs.class);
|
||||
result.addTestSuite(TestFormulasFromSpreadsheet.class);
|
||||
|
@ -93,7 +93,6 @@ public final class TestCircularReferences extends TestCase {
|
||||
HSSFCell testCell = row.createCell(0);
|
||||
testCell.setCellFormula("A1");
|
||||
|
||||
HSSFFormulaEvaluator evaluator = new HSSFFormulaEvaluator(sheet, wb);
|
||||
CellValue cellValue = evaluateWithCycles(wb, sheet, testCell);
|
||||
|
||||
confirmCycleErrorCode(cellValue);
|
||||
@ -114,7 +113,6 @@ public final class TestCircularReferences extends TestCase {
|
||||
HSSFCell testCell = row.createCell(3);
|
||||
testCell.setCellFormula("A1");
|
||||
|
||||
HSSFFormulaEvaluator evaluator = new HSSFFormulaEvaluator(sheet, wb);
|
||||
CellValue cellValue = evaluateWithCycles(wb, sheet, testCell);
|
||||
|
||||
confirmCycleErrorCode(cellValue);
|
||||
|
@ -0,0 +1,62 @@
|
||||
/* ====================================================================
|
||||
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 junit.framework.TestCase;
|
||||
|
||||
import org.apache.poi.hssf.record.formula.functions.EvalFactory;
|
||||
import org.apache.poi.hssf.record.formula.functions.NumericFunctionInvoker;
|
||||
|
||||
/**
|
||||
* Test for divide operator evaluator.
|
||||
*
|
||||
* @author Josh Micich
|
||||
*/
|
||||
public final class TestDivideEval extends TestCase {
|
||||
|
||||
private static void confirm(ValueEval arg0, ValueEval arg1, double expectedResult) {
|
||||
Eval[] args = {
|
||||
arg0, arg1,
|
||||
};
|
||||
|
||||
double result = NumericFunctionInvoker.invoke(DivideEval.instance, args, 0, 0);
|
||||
|
||||
assertEquals(expectedResult, result, 0);
|
||||
}
|
||||
|
||||
public void testBasic() {
|
||||
confirm(new NumberEval(5), new NumberEval(2), 2.5);
|
||||
confirm(new NumberEval(3), new NumberEval(16), 0.1875);
|
||||
confirm(new NumberEval(-150), new NumberEval(-15), 10.0);
|
||||
confirm(new StringEval("0.2"), new NumberEval(0.05), 4.0);
|
||||
confirm(BoolEval.TRUE, new StringEval("-0.2"), -5.0);
|
||||
}
|
||||
|
||||
public void test1x1Area() {
|
||||
AreaEval ae0 = EvalFactory.createAreaEval("B2:B2", new ValueEval[] { new NumberEval(50), });
|
||||
AreaEval ae1 = EvalFactory.createAreaEval("C2:C2", new ValueEval[] { new NumberEval(10), });
|
||||
confirm(ae0, ae1, 5);
|
||||
}
|
||||
public void testDivZero() {
|
||||
Eval[] args = {
|
||||
new NumberEval(5), NumberEval.ZERO,
|
||||
};
|
||||
Eval result = DivideEval.instance.evaluate(args, 0, (short) 0);
|
||||
assertEquals(ErrorEval.DIV_ZERO, result);
|
||||
}
|
||||
}
|
@ -0,0 +1,69 @@
|
||||
/* ====================================================================
|
||||
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 junit.framework.AssertionFailedError;
|
||||
import junit.framework.TestCase;
|
||||
|
||||
import org.apache.poi.hssf.record.formula.functions.EvalFactory;
|
||||
|
||||
/**
|
||||
* Test for unary plus operator evaluator.
|
||||
*
|
||||
* @author Josh Micich
|
||||
*/
|
||||
public final class TestEqualEval extends TestCase {
|
||||
|
||||
/**
|
||||
* Test for bug observable at svn revision 692218 (Sep 2008)<br/>
|
||||
* The value from a 1x1 area should be taken immediately, regardless of srcRow and srcCol
|
||||
*/
|
||||
public void test1x1AreaOperand() {
|
||||
|
||||
ValueEval[] values = { BoolEval.FALSE, };
|
||||
Eval[] args = {
|
||||
EvalFactory.createAreaEval("B1:B1", values),
|
||||
BoolEval.FALSE,
|
||||
};
|
||||
Eval result = EqualEval.instance.evaluate(args, 10, (short)20);
|
||||
if (result instanceof ErrorEval) {
|
||||
if (result == ErrorEval.VALUE_INVALID) {
|
||||
throw new AssertionFailedError("Identified bug in evaluation of 1x1 area");
|
||||
}
|
||||
}
|
||||
assertEquals(BoolEval.class, result.getClass());
|
||||
assertTrue(((BoolEval)result).getBooleanValue());
|
||||
}
|
||||
/**
|
||||
* Empty string is equal to blank
|
||||
*/
|
||||
public void testBlankEqualToEmptyString() {
|
||||
|
||||
Eval[] args = {
|
||||
new StringEval(""),
|
||||
BlankEval.INSTANCE,
|
||||
};
|
||||
Eval result = EqualEval.instance.evaluate(args, 10, (short)20);
|
||||
assertEquals(BoolEval.class, result.getClass());
|
||||
BoolEval be = (BoolEval) result;
|
||||
if (!be.getBooleanValue()) {
|
||||
throw new AssertionFailedError("Identified bug blank/empty string equality");
|
||||
}
|
||||
assertTrue(be.getBooleanValue());
|
||||
}
|
||||
}
|
@ -20,7 +20,7 @@ package org.apache.poi.hssf.record.formula.eval;
|
||||
import junit.framework.AssertionFailedError;
|
||||
import junit.framework.TestCase;
|
||||
|
||||
import org.apache.poi.hssf.record.formula.PercentPtg;
|
||||
import org.apache.poi.hssf.record.formula.functions.EvalFactory;
|
||||
import org.apache.poi.hssf.record.formula.functions.NumericFunctionInvoker;
|
||||
import org.apache.poi.hssf.usermodel.HSSFCell;
|
||||
import org.apache.poi.hssf.usermodel.HSSFFormulaEvaluator;
|
||||
@ -41,8 +41,8 @@ public final class TestPercentEval extends TestCase {
|
||||
arg,
|
||||
};
|
||||
|
||||
PercentEval opEval = new PercentEval(PercentPtg.instance);
|
||||
double result = NumericFunctionInvoker.invoke(opEval, args, -1, (short)-1);
|
||||
OperationEval opEval = PercentEval.instance;
|
||||
double result = NumericFunctionInvoker.invoke(opEval, args, 0, 0);
|
||||
|
||||
assertEquals(expectedResult, result, 0);
|
||||
}
|
||||
@ -55,6 +55,10 @@ public final class TestPercentEval extends TestCase {
|
||||
confirm(BoolEval.TRUE, 0.01);
|
||||
}
|
||||
|
||||
public void test1x1Area() {
|
||||
AreaEval ae = EvalFactory.createAreaEval("B2:B2", new ValueEval[] { new NumberEval(50), });
|
||||
confirm(ae, 0.5);
|
||||
}
|
||||
public void testInSpreadSheet() {
|
||||
HSSFWorkbook wb = new HSSFWorkbook();
|
||||
HSSFSheet sheet = wb.createSheet("Sheet1");
|
||||
|
@ -1,27 +1,25 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
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;
|
||||
|
||||
@ -53,7 +51,7 @@ public final class TestUnaryPlusEval extends TestCase {
|
||||
EvalFactory.createAreaEval(areaPtg, values),
|
||||
};
|
||||
|
||||
double result = NumericFunctionInvoker.invoke(new UnaryPlusEval(UnaryPlusPtg.instance), args, 10, (short)20);
|
||||
double result = NumericFunctionInvoker.invoke(UnaryPlusEval.instance, args, 10, (short)20);
|
||||
|
||||
assertEquals(35, result, 0);
|
||||
}
|
||||
|
@ -36,6 +36,7 @@ public final class AllIndividualFunctionEvaluationTests {
|
||||
result.addTestSuite(TestIndex.class);
|
||||
result.addTestSuite(TestIsBlank.class);
|
||||
result.addTestSuite(TestLen.class);
|
||||
result.addTestSuite(TestLookupFunctionsFromSpreadsheet.class);
|
||||
result.addTestSuite(TestMid.class);
|
||||
result.addTestSuite(TestMathX.class);
|
||||
result.addTestSuite(TestMatch.class);
|
||||
|
@ -28,29 +28,29 @@ import org.apache.poi.hssf.usermodel.HSSFWorkbook;
|
||||
* @author Pavel Krupets (pkrupets at palmtreebusiness dot com)
|
||||
*/
|
||||
public final class TestDate extends TestCase {
|
||||
|
||||
|
||||
private HSSFCell cell11;
|
||||
private HSSFFormulaEvaluator evaluator;
|
||||
|
||||
public void setUp() {
|
||||
HSSFWorkbook wb = new HSSFWorkbook();
|
||||
HSSFSheet sheet = wb.createSheet("new sheet");
|
||||
cell11 = sheet.createRow(0).createCell(0);
|
||||
cell11 = sheet.createRow(0).createCell(0);
|
||||
cell11.setCellType(HSSFCell.CELL_TYPE_FORMULA);
|
||||
evaluator = new HSSFFormulaEvaluator(sheet, wb);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test disabled pending a fix in the formula evaluator
|
||||
* TODO - create MissingArgEval and modify the formula evaluator to handle this
|
||||
*/
|
||||
|
||||
/**
|
||||
* Test disabled pending a fix in the formula evaluator
|
||||
* TODO - create MissingArgEval and modify the formula evaluator to handle this
|
||||
*/
|
||||
public void DISABLEDtestSomeArgumentsMissing() {
|
||||
confirm("DATE(, 1, 0)", 0.0);
|
||||
confirm("DATE(, 1, 1)", 1.0);
|
||||
}
|
||||
|
||||
|
||||
public void testValid() {
|
||||
|
||||
|
||||
confirm("DATE(1900, 1, 1)", 1);
|
||||
confirm("DATE(1900, 1, 32)", 32);
|
||||
confirm("DATE(1900, 222, 1)", 6727);
|
||||
@ -58,7 +58,7 @@ public final class TestDate extends TestCase {
|
||||
confirm("DATE(2000, 1, 222)", 36747.00);
|
||||
confirm("DATE(2007, 1, 1)", 39083);
|
||||
}
|
||||
|
||||
|
||||
public void testBugDate() {
|
||||
confirm("DATE(1900, 2, 29)", 60);
|
||||
confirm("DATE(1900, 2, 30)", 61);
|
||||
@ -66,7 +66,7 @@ public final class TestDate extends TestCase {
|
||||
confirm("DATE(1900, 1, 2222)", 2222);
|
||||
confirm("DATE(1900, 1, 22222)", 22222);
|
||||
}
|
||||
|
||||
|
||||
public void testPartYears() {
|
||||
confirm("DATE(4, 1, 1)", 1462.00);
|
||||
confirm("DATE(14, 1, 1)", 5115.00);
|
||||
@ -74,10 +74,11 @@ public final class TestDate extends TestCase {
|
||||
confirm("DATE(1004, 1, 1)", 366705.00);
|
||||
}
|
||||
|
||||
private void confirm(String formulaText, double expectedResult) {
|
||||
private void confirm(String formulaText, double expectedResult) {
|
||||
cell11.setCellFormula(formulaText);
|
||||
evaluator.clearCache();
|
||||
double actualValue = evaluator.evaluate(cell11).getNumberValue();
|
||||
assertEquals(expectedResult, actualValue, 0);
|
||||
}
|
||||
assertEquals(expectedResult, actualValue, 0);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -46,6 +46,7 @@ public class AllUserModelTests {
|
||||
result.addTestSuite(TestHSSFConditionalFormatting.class);
|
||||
result.addTestSuite(TestHSSFDataFormatter.class);
|
||||
result.addTestSuite(TestHSSFDateUtil.class);
|
||||
result.addTestSuite(TestHSSFFormulaEvaluator.class);
|
||||
result.addTestSuite(TestHSSFHeaderFooter.class);
|
||||
result.addTestSuite(TestHSSFHyperlink.class);
|
||||
result.addTestSuite(TestHSSFOptimiser.class);
|
||||
|
@ -37,6 +37,7 @@ import org.apache.poi.hssf.record.EmbeddedObjectRefSubRecord;
|
||||
import org.apache.poi.hssf.record.NameRecord;
|
||||
import org.apache.poi.hssf.record.aggregates.FormulaRecordAggregate;
|
||||
import org.apache.poi.hssf.record.formula.DeletedArea3DPtg;
|
||||
import org.apache.poi.hssf.record.formula.Ptg;
|
||||
import org.apache.poi.util.TempFile;
|
||||
|
||||
/**
|
||||
@ -1020,9 +1021,9 @@ public final class TestBugs extends TestCase {
|
||||
NameRecord r = w.getNameRecord(i);
|
||||
assertTrue(r.getSheetNumber() <= wb.getNumberOfSheets());
|
||||
|
||||
List nd = r.getNameDefinition();
|
||||
assertEquals(1, nd.size());
|
||||
assertTrue(nd.get(0) instanceof DeletedArea3DPtg);
|
||||
Ptg[] nd = r.getNameDefinition();
|
||||
assertEquals(1, nd.length);
|
||||
assertTrue(nd[0] instanceof DeletedArea3DPtg);
|
||||
}
|
||||
|
||||
|
||||
@ -1038,9 +1039,9 @@ public final class TestBugs extends TestCase {
|
||||
NameRecord r = w.getNameRecord(i);
|
||||
assertTrue(r.getSheetNumber() <= wb.getNumberOfSheets());
|
||||
|
||||
List nd = r.getNameDefinition();
|
||||
assertEquals(1, nd.size());
|
||||
assertTrue(nd.get(0) instanceof DeletedArea3DPtg);
|
||||
Ptg[] nd = r.getNameDefinition();
|
||||
assertEquals(1, nd.length);
|
||||
assertTrue(nd[0] instanceof DeletedArea3DPtg);
|
||||
}
|
||||
|
||||
|
||||
@ -1055,9 +1056,9 @@ public final class TestBugs extends TestCase {
|
||||
NameRecord r = w.getNameRecord(i);
|
||||
assertTrue(r.getSheetNumber() <= wb.getNumberOfSheets());
|
||||
|
||||
List nd = r.getNameDefinition();
|
||||
assertEquals(1, nd.size());
|
||||
assertTrue(nd.get(0) instanceof DeletedArea3DPtg);
|
||||
Ptg[] nd = r.getNameDefinition();
|
||||
assertEquals(1, nd.length);
|
||||
assertTrue(nd[0] instanceof DeletedArea3DPtg);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -19,6 +19,8 @@ package org.apache.poi.hssf.usermodel;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.util.Calendar;
|
||||
import java.util.GregorianCalendar;
|
||||
import java.util.Iterator;
|
||||
|
||||
import junit.framework.AssertionFailedError;
|
||||
@ -35,6 +37,7 @@ import org.apache.poi.hssf.record.formula.Ptg;
|
||||
*/
|
||||
public final class TestFormulaEvaluatorBugs extends TestCase {
|
||||
|
||||
private static final boolean OUTPUT_TEST_FILES = false;
|
||||
private String tmpDirName;
|
||||
|
||||
protected void setUp() {
|
||||
@ -65,13 +68,15 @@ public final class TestFormulaEvaluatorBugs extends TestCase {
|
||||
HSSFFormulaEvaluator.evaluateAllFormulaCells(wb);
|
||||
assertEquals(4.2 * 25, row.getCell(3).getNumericCellValue(), 0.0001);
|
||||
|
||||
// Save
|
||||
File existing = new File(tmpDirName, "44636-existing.xls");
|
||||
FileOutputStream out = new FileOutputStream(existing);
|
||||
wb.write(out);
|
||||
out.close();
|
||||
System.err.println("Existing file for bug #44636 written to " + existing.toString());
|
||||
|
||||
FileOutputStream out;
|
||||
if (OUTPUT_TEST_FILES) {
|
||||
// Save
|
||||
File existing = new File(tmpDirName, "44636-existing.xls");
|
||||
out = new FileOutputStream(existing);
|
||||
wb.write(out);
|
||||
out.close();
|
||||
System.err.println("Existing file for bug #44636 written to " + existing.toString());
|
||||
}
|
||||
// Now, do a new file from scratch
|
||||
wb = new HSSFWorkbook();
|
||||
sheet = wb.createSheet();
|
||||
@ -86,12 +91,14 @@ public final class TestFormulaEvaluatorBugs extends TestCase {
|
||||
HSSFFormulaEvaluator.evaluateAllFormulaCells(wb);
|
||||
assertEquals(5.4, row.getCell(0).getNumericCellValue(), 0.0001);
|
||||
|
||||
// Save
|
||||
File scratch = new File(tmpDirName, "44636-scratch.xls");
|
||||
out = new FileOutputStream(scratch);
|
||||
wb.write(out);
|
||||
out.close();
|
||||
System.err.println("New file for bug #44636 written to " + scratch.toString());
|
||||
if (OUTPUT_TEST_FILES) {
|
||||
// Save
|
||||
File scratch = new File(tmpDirName, "44636-scratch.xls");
|
||||
out = new FileOutputStream(scratch);
|
||||
wb.write(out);
|
||||
out.close();
|
||||
System.err.println("New file for bug #44636 written to " + scratch.toString());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -281,64 +288,39 @@ public final class TestFormulaEvaluatorBugs extends TestCase {
|
||||
}
|
||||
|
||||
/**
|
||||
* Apparently, each subsequent call takes longer, which is very
|
||||
* odd.
|
||||
* We think it's because the formulas are recursive and crazy
|
||||
* The HSSFFormula evaluator performance benefits greatly from caching of intermediate cell values
|
||||
*/
|
||||
public void DISABLEDtestSlowEvaluate45376() throws Exception {
|
||||
HSSFWorkbook wb = HSSFTestDataSamples.openSampleWorkbook("45376.xls");
|
||||
public void testSlowEvaluate45376() {
|
||||
|
||||
final String SHEET_NAME = "Eingabe";
|
||||
final int row = 6;
|
||||
final HSSFSheet sheet = wb.getSheet(SHEET_NAME);
|
||||
|
||||
int firstCol = 4;
|
||||
int lastCol = 14;
|
||||
long[] timings = new long[lastCol-firstCol+1];
|
||||
long[] rtimings = new long[lastCol-firstCol+1];
|
||||
|
||||
long then, now;
|
||||
|
||||
final HSSFRow excelRow = sheet.getRow(row);
|
||||
for(int i = firstCol; i <= lastCol; i++) {
|
||||
final HSSFCell excelCell = excelRow.getCell(i);
|
||||
final HSSFFormulaEvaluator evaluator = new
|
||||
HSSFFormulaEvaluator(sheet, wb);
|
||||
|
||||
now = System.currentTimeMillis();
|
||||
evaluator.evaluate(excelCell);
|
||||
then = System.currentTimeMillis();
|
||||
timings[i-firstCol] = (then-now);
|
||||
System.err.println("Col " + i + " took " + (then-now) + "ms");
|
||||
}
|
||||
for(int i = lastCol; i >= firstCol; i--) {
|
||||
final HSSFCell excelCell = excelRow.getCell(i);
|
||||
final HSSFFormulaEvaluator evaluator = new
|
||||
HSSFFormulaEvaluator(sheet, wb);
|
||||
|
||||
now = System.currentTimeMillis();
|
||||
evaluator.evaluate(excelCell);
|
||||
then = System.currentTimeMillis();
|
||||
rtimings[i-firstCol] = (then-now);
|
||||
System.err.println("Col " + i + " took " + (then-now) + "ms");
|
||||
}
|
||||
|
||||
// The timings for each should be about the same
|
||||
long avg = 0;
|
||||
for(int i=0; i<timings.length; i++) {
|
||||
avg += timings[i];
|
||||
}
|
||||
avg = (long)( ((double)avg) / timings.length );
|
||||
|
||||
// Warn if any took more then 1.5 the average
|
||||
// TODO - replace with assert or similar
|
||||
for(int i=0; i<timings.length; i++) {
|
||||
if(timings[i] > 1.5*avg) {
|
||||
System.err.println("Doing col " + (i+firstCol) +
|
||||
" took " + timings[i] + "ms, vs avg " +
|
||||
avg + "ms"
|
||||
);
|
||||
}
|
||||
}
|
||||
// Firstly set up a sequence of formula cells where each depends on the previous multiple
|
||||
// times. Without caching, each subsequent cell take about 4 times longer to evaluate.
|
||||
HSSFWorkbook wb = new HSSFWorkbook();
|
||||
HSSFSheet sheet = wb.createSheet("Sheet1");
|
||||
HSSFRow row = sheet.createRow(0);
|
||||
for(int i=1; i<10; i++) {
|
||||
HSSFCell cell = row.createCell(i);
|
||||
char prevCol = (char) ('A' + i-1);
|
||||
String prevCell = prevCol + "1";
|
||||
// this formula is inspired by the offending formula of the attachment for bug 45376
|
||||
String formula = "IF(DATE(YEAR(" + prevCell + "),MONTH(" + prevCell + ")+1,1)<=$D$3," +
|
||||
"DATE(YEAR(" + prevCell + "),MONTH(" + prevCell + ")+1,1),NA())";
|
||||
cell.setCellFormula(formula);
|
||||
|
||||
}
|
||||
Calendar cal = new GregorianCalendar(2000, 0, 1, 0, 0, 0);
|
||||
row.createCell(0).setCellValue(cal);
|
||||
|
||||
// Choose cell A9, so that the failing test case doesn't take too long to execute.
|
||||
HSSFCell cell = row.getCell(8);
|
||||
HSSFFormulaEvaluator evaluator = new HSSFFormulaEvaluator(sheet, wb);
|
||||
evaluator.evaluate(cell);
|
||||
int evalCount = evaluator.getEvaluationCount();
|
||||
// With caching, the evaluationCount is 8 which is a big improvement
|
||||
if (evalCount > 10) {
|
||||
// Without caching, evaluating cell 'A9' takes 21845 evaluations which consumes
|
||||
// much time (~3 sec on Core 2 Duo 2.2GHz)
|
||||
System.err.println("Cell A9 took " + evalCount + " intermediate evaluations");
|
||||
throw new AssertionFailedError("Identifed bug 45376 - Formula evaluator should cache values");
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,82 @@
|
||||
/* ====================================================================
|
||||
Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
contributor license agreements. See the NOTICE file distributed with
|
||||
this work for additional information regarding copyright ownership.
|
||||
The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
(the "License"); you may not use this file except in compliance with
|
||||
the License. You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
==================================================================== */
|
||||
|
||||
package org.apache.poi.hssf.usermodel;
|
||||
|
||||
import org.apache.poi.hssf.HSSFTestDataSamples;
|
||||
import org.apache.poi.ss.usermodel.FormulaEvaluator.CellValue;
|
||||
|
||||
import junit.framework.TestCase;
|
||||
/**
|
||||
*
|
||||
* @author Josh Micich
|
||||
*/
|
||||
public final class TestHSSFFormulaEvaluator extends TestCase {
|
||||
|
||||
/**
|
||||
* Test that the HSSFFormulaEvaluator can evaluate simple named ranges
|
||||
* (single cells and rectangular areas)
|
||||
*/
|
||||
public void testEvaluateSimple() {
|
||||
HSSFWorkbook wb = HSSFTestDataSamples.openSampleWorkbook("testNames.xls");
|
||||
HSSFSheet sheet = wb.getSheetAt(0);
|
||||
HSSFCell cell = sheet.getRow(8).getCell(0);
|
||||
HSSFFormulaEvaluator fe = new HSSFFormulaEvaluator(sheet, wb);
|
||||
CellValue cv = fe.evaluate(cell);
|
||||
assertEquals(HSSFCell.CELL_TYPE_NUMERIC, cv.getCellType());
|
||||
assertEquals(3.72, cv.getNumberValue(), 0.0);
|
||||
}
|
||||
|
||||
public void testFullColumnRefs() {
|
||||
HSSFWorkbook wb = new HSSFWorkbook();
|
||||
HSSFSheet sheet = wb.createSheet("Sheet1");
|
||||
HSSFRow row = sheet.createRow(0);
|
||||
HSSFCell cell0 = row.createCell(0);
|
||||
cell0.setCellFormula("sum(D:D)");
|
||||
HSSFCell cell1 = row.createCell(1);
|
||||
cell1.setCellFormula("sum(D:E)");
|
||||
|
||||
// some values in column D
|
||||
setValue(sheet, 1, 3, 5.0);
|
||||
setValue(sheet, 2, 3, 6.0);
|
||||
setValue(sheet, 5, 3, 7.0);
|
||||
setValue(sheet, 50, 3, 8.0);
|
||||
|
||||
// some values in column E
|
||||
setValue(sheet, 1, 4, 9.0);
|
||||
setValue(sheet, 2, 4, 10.0);
|
||||
setValue(sheet, 30000, 4, 11.0);
|
||||
|
||||
// some other values
|
||||
setValue(sheet, 1, 2, 100.0);
|
||||
setValue(sheet, 2, 5, 100.0);
|
||||
setValue(sheet, 3, 6, 100.0);
|
||||
|
||||
|
||||
HSSFFormulaEvaluator fe = new HSSFFormulaEvaluator(sheet, wb);
|
||||
assertEquals(26.0, fe.evaluate(cell0).getNumberValue(), 0.0);
|
||||
assertEquals(56.0, fe.evaluate(cell1).getNumberValue(), 0.0);
|
||||
}
|
||||
|
||||
private static void setValue(HSSFSheet sheet, int rowIndex, int colIndex, double value) {
|
||||
HSSFRow row = sheet.getRow(rowIndex);
|
||||
if (row == null) {
|
||||
row = sheet.createRow(rowIndex);
|
||||
}
|
||||
row.createCell(colIndex).setCellValue(value);
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load Diff
@ -429,9 +429,9 @@ public final class TestHSSFWorkbook extends TestCase {
|
||||
assertEquals("On2", nr.getNameText());
|
||||
assertEquals(0, nr.getSheetNumber());
|
||||
assertEquals(1, nr.getExternSheetNumber());
|
||||
assertEquals(1, nr.getNameDefinition().size());
|
||||
assertEquals(1, nr.getNameDefinition().length);
|
||||
|
||||
ptg = (Area3DPtg)nr.getNameDefinition().get(0);
|
||||
ptg = (Area3DPtg)nr.getNameDefinition()[0];
|
||||
assertEquals(1, ptg.getExternSheetIndex());
|
||||
assertEquals(0, ptg.getFirstColumn());
|
||||
assertEquals(0, ptg.getFirstRow());
|
||||
@ -452,9 +452,9 @@ public final class TestHSSFWorkbook extends TestCase {
|
||||
assertEquals("OnOne", nr.getNameText());
|
||||
assertEquals(0, nr.getSheetNumber());
|
||||
assertEquals(0, nr.getExternSheetNumber());
|
||||
assertEquals(1, nr.getNameDefinition().size());
|
||||
assertEquals(1, nr.getNameDefinition().length);
|
||||
|
||||
ptg = (Area3DPtg)nr.getNameDefinition().get(0);
|
||||
ptg = (Area3DPtg)nr.getNameDefinition()[0];
|
||||
assertEquals(0, ptg.getExternSheetIndex());
|
||||
assertEquals(0, ptg.getFirstColumn());
|
||||
assertEquals(2, ptg.getFirstRow());
|
||||
@ -475,9 +475,9 @@ public final class TestHSSFWorkbook extends TestCase {
|
||||
assertEquals("OnSheet3", nr.getNameText());
|
||||
assertEquals(0, nr.getSheetNumber());
|
||||
assertEquals(2, nr.getExternSheetNumber());
|
||||
assertEquals(1, nr.getNameDefinition().size());
|
||||
assertEquals(1, nr.getNameDefinition().length);
|
||||
|
||||
ptg = (Area3DPtg)nr.getNameDefinition().get(0);
|
||||
ptg = (Area3DPtg)nr.getNameDefinition()[0];
|
||||
assertEquals(2, ptg.getExternSheetIndex());
|
||||
assertEquals(0, ptg.getFirstColumn());
|
||||
assertEquals(0, ptg.getFirstRow());
|
||||
|
@ -19,7 +19,6 @@ package org.apache.poi.hssf.util;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.List;
|
||||
|
||||
import junit.framework.TestCase;
|
||||
|
||||
@ -28,6 +27,7 @@ import org.apache.poi.hssf.model.Workbook;
|
||||
import org.apache.poi.hssf.record.NameRecord;
|
||||
import org.apache.poi.hssf.record.formula.Area3DPtg;
|
||||
import org.apache.poi.hssf.record.formula.MemFuncPtg;
|
||||
import org.apache.poi.hssf.record.formula.Ptg;
|
||||
import org.apache.poi.hssf.record.formula.UnionPtg;
|
||||
import org.apache.poi.hssf.usermodel.HSSFCell;
|
||||
import org.apache.poi.hssf.usermodel.HSSFName;
|
||||
@ -85,7 +85,7 @@ public final class TestAreaReference extends TestCase {
|
||||
public void testReferenceWithSheet() {
|
||||
AreaReference ar;
|
||||
|
||||
ar = new AreaReference("Tabelle1!B5");
|
||||
ar = new AreaReference("Tabelle1!B5:B5");
|
||||
assertTrue(ar.isSingleCell());
|
||||
TestCellReference.confirmCell(ar.getFirstCell(), "Tabelle1", 4, 1, false, false, "Tabelle1!B5");
|
||||
|
||||
@ -115,11 +115,11 @@ public final class TestAreaReference extends TestCase {
|
||||
}
|
||||
}
|
||||
|
||||
public void testContiguousReferences() throws Exception {
|
||||
String refSimple = "$C$10";
|
||||
public void testContiguousReferences() {
|
||||
String refSimple = "$C$10:$C$10";
|
||||
String ref2D = "$C$10:$D$11";
|
||||
String refDCSimple = "$C$10,$D$12,$E$14";
|
||||
String refDC2D = "$C$10:$C$11,$D$12,$E$14:$E$20";
|
||||
String refDCSimple = "$C$10:$C$10,$D$12:$D$12,$E$14:$E$14";
|
||||
String refDC2D = "$C$10:$C$11,$D$12:$D$12,$E$14:$E$20";
|
||||
String refDC3D = "Tabelle1!$C$10:$C$14,Tabelle1!$D$10:$D$12";
|
||||
|
||||
// Check that we detect as contiguous properly
|
||||
@ -206,13 +206,13 @@ public final class TestAreaReference extends TestCase {
|
||||
assertNotNull(nr);
|
||||
assertEquals("test", nr.getNameText());
|
||||
|
||||
List def =nr.getNameDefinition();
|
||||
assertEquals(4, def.size());
|
||||
Ptg[] def =nr.getNameDefinition();
|
||||
assertEquals(4, def.length);
|
||||
|
||||
MemFuncPtg ptgA = (MemFuncPtg)def.get(0);
|
||||
Area3DPtg ptgB = (Area3DPtg)def.get(1);
|
||||
Area3DPtg ptgC = (Area3DPtg)def.get(2);
|
||||
UnionPtg ptgD = (UnionPtg)def.get(3);
|
||||
MemFuncPtg ptgA = (MemFuncPtg)def[0];
|
||||
Area3DPtg ptgB = (Area3DPtg)def[1];
|
||||
Area3DPtg ptgC = (Area3DPtg)def[2];
|
||||
UnionPtg ptgD = (UnionPtg)def[3];
|
||||
assertEquals("", ptgA.toFormulaString(wb));
|
||||
assertEquals(refA, ptgB.toFormulaString(wb));
|
||||
assertEquals(refB, ptgC.toFormulaString(wb));
|
||||
@ -245,16 +245,16 @@ public final class TestAreaReference extends TestCase {
|
||||
private static void confirmResolveCellRef(HSSFWorkbook wb, CellReference cref) {
|
||||
HSSFSheet s = wb.getSheet(cref.getSheetName());
|
||||
HSSFRow r = s.getRow(cref.getRow());
|
||||
HSSFCell c = r.getCell(cref.getCol());
|
||||
HSSFCell c = r.getCell((int)cref.getCol());
|
||||
assertNotNull(c);
|
||||
}
|
||||
|
||||
public void testSpecialSheetNames() {
|
||||
AreaReference ar;
|
||||
ar = new AreaReference("'Sheet A'!A1");
|
||||
ar = new AreaReference("'Sheet A'!A1:A1");
|
||||
confirmAreaSheetName(ar, "Sheet A", "'Sheet A'!A1");
|
||||
|
||||
ar = new AreaReference("'Hey! Look Here!'!A1");
|
||||
ar = new AreaReference("'Hey! Look Here!'!A1:A1");
|
||||
confirmAreaSheetName(ar, "Hey! Look Here!", "'Hey! Look Here!'!A1");
|
||||
|
||||
ar = new AreaReference("'O''Toole'!A1:B2");
|
||||
@ -270,7 +270,24 @@ public final class TestAreaReference extends TestCase {
|
||||
assertEquals(expectedFullText, ar.formatAsString());
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
junit.textui.TestRunner.run(TestAreaReference.class);
|
||||
}
|
||||
public void testWholeColumnRefs() {
|
||||
confirmWholeColumnRef("A:A", 0, 0, false, false);
|
||||
confirmWholeColumnRef("$C:D", 2, 3, true, false);
|
||||
confirmWholeColumnRef("AD:$AE", 29, 30, false, true);
|
||||
|
||||
}
|
||||
|
||||
private static void confirmWholeColumnRef(String ref, int firstCol, int lastCol, boolean firstIsAbs, boolean lastIsAbs) {
|
||||
AreaReference ar = new AreaReference(ref);
|
||||
confirmCell(ar.getFirstCell(), 0, firstCol, true, firstIsAbs);
|
||||
confirmCell(ar.getLastCell(), 0xFFFF, lastCol, true, lastIsAbs);
|
||||
}
|
||||
|
||||
private static void confirmCell(CellReference cell, int row, int col, boolean isRowAbs,
|
||||
boolean isColAbs) {
|
||||
assertEquals(row, cell.getRow());
|
||||
assertEquals(col, cell.getCol());
|
||||
assertEquals(isRowAbs, cell.isRowAbsolute());
|
||||
assertEquals(isColAbs, cell.isColAbsolute());
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user