From 7df799556d6239e27106a1ac33864c70acfa4e8f Mon Sep 17 00:00:00 2001 From: Nick Burch Date: Wed, 27 Aug 2008 10:34:33 +0000 Subject: [PATCH] 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-689430 via svnmerge from https://svn.apache.org/repos/asf/poi/trunk ........ r687403 | nick | 2008-08-20 19:14:11 +0100 (Wed, 20 Aug 2008) | 1 line Make an initial start on hpbf code ........ r687423 | nick | 2008-08-20 19:50:15 +0100 (Wed, 20 Aug 2008) | 1 line More HPBF stuff, and some tests ........ r687429 | nick | 2008-08-20 20:40:05 +0100 (Wed, 20 Aug 2008) | 1 line Quill CONTENTS bits, and tests ........ r687443 | nick | 2008-08-20 21:13:08 +0100 (Wed, 20 Aug 2008) | 1 line HPBF text extractor and unit tests ........ r688426 | josh | 2008-08-23 23:47:51 +0100 (Sat, 23 Aug 2008) | 1 line Fix for bug 45672 - prevent MissingRecordAwareHSSFListener generating multiple LastCellOfRowDummyRecords when shared formulas are present ........ r688642 | josh | 2008-08-25 08:56:37 +0100 (Mon, 25 Aug 2008) | 1 line JDK 1.4 fixes for new hpbf stuff. Some clean-up ........ r688650 | josh | 2008-08-25 09:09:02 +0100 (Mon, 25 Aug 2008) | 1 line Initial support for evaluating external add-in functions like YEARFRAC ........ r688655 | josh | 2008-08-25 09:30:54 +0100 (Mon, 25 Aug 2008) | 1 line Fix for bug 45682 - allow cloning of sheets with conditional formatting ........ r688825 | josh | 2008-08-25 19:57:14 +0100 (Mon, 25 Aug 2008) | 1 line Fix for small bug introduced in c688655 - keep header field in sync with number of rules ........ r688910 | josh | 2008-08-25 23:41:08 +0100 (Mon, 25 Aug 2008) | 1 line Replaced calls to deprecated versions of createCell(), getCell(), createRow(), and getRow(). (Changing short to int) ........ git-svn-id: https://svn.apache.org/repos/asf/poi/branches/ooxml@689435 13f79535-47bb-0310-9956-ffa450edef68 --- .../hssf/usermodel/contrib/HSSFCellUtil.java | 2 +- src/documentation/content/xdocs/changes.xml | 3 + src/documentation/content/xdocs/status.xml | 3 + src/java/org/apache/poi/hssf/dev/HSSF.java | 4 +- .../MissingRecordAwareHSSFListener.java | 196 ++++------ .../poi/hssf/extractor/ExcelExtractor.java | 2 +- .../poi/hssf/record/CFHeaderRecord.java | 4 +- .../apache/poi/hssf/record/SupBookRecord.java | 1 + .../record/aggregates/CFRecordsAggregate.java | 89 +---- .../ConditionalFormattingTable.java | 4 +- .../poi/hssf/record/formula/NameXPtg.java | 13 +- .../record/formula/atp/AnalysisToolPak.java | 154 ++++++++ .../poi/hssf/record/formula/atp/YearFrac.java | 160 ++++++++ .../formula/atp/YearFracCalculator.java | 344 ++++++++++++++++++ .../record/formula/eval/ExternalFunction.java | 50 ++- .../hssf/record/formula/eval/NameXEval.java | 49 +++ .../HSSFConditionalFormattingRule.java | 6 + .../apache/poi/hssf/usermodel/HSSFRow.java | 2 +- .../apache/poi/hssf/usermodel/HSSFSheet.java | 2 +- .../org/apache/poi/ss/usermodel/DateUtil.java | 15 +- .../poi/ss/usermodel/FormulaEvaluator.java | 4 +- .../src/org/apache/poi/hpbf/HPBFDocument.java | 86 +++++ .../extractor/PublisherTextExtractor.java | 78 ++++ .../apache/poi/hpbf/model/EscherDelayStm.java | 30 ++ .../org/apache/poi/hpbf/model/EscherPart.java | 80 ++++ .../org/apache/poi/hpbf/model/EscherStm.java | 29 ++ .../org/apache/poi/hpbf/model/HPBFPart.java | 104 ++++++ .../apache/poi/hpbf/model/MainContents.java | 38 ++ .../apache/poi/hpbf/model/QuillContents.java | 87 +++++ .../apache/poi/hpbf/model/qcbits/QCBit.java | 69 ++++ .../poi/hpbf/model/qcbits/QCTextBit.java | 43 +++ .../poi/hpbf/model/qcbits/UnknownQCBit.java | 27 ++ .../org/apache/poi/hpbf/TestHPBFDocument.java | 60 +++ .../org/apache/poi/hpbf/data/Simple.pub | Bin 0 -> 65536 bytes .../extractor/TextPublisherTextExtractor.java | 105 ++++++ .../poi/hpbf/model/TestEscherParts.java | 50 +++ .../poi/hpbf/model/TestQuillContents.java | 80 ++++ .../org/apache/poi/hssf/data/ex45672.xls | Bin 0 -> 16384 bytes .../apache/poi/hssf/data/yearfracExamples.xls | Bin 0 -> 29184 bytes .../poi/hssf/eventmodel/TestModelFactory.java | 2 +- .../TestMissingRecordAwareHSSFListener.java | 116 +++--- .../apache/poi/hssf/record/TestSSTRecord.java | 16 +- .../aggregates/TestCFRecordsAggregate.java | 29 +- .../aggregates/TestValueRecordsAggregate.java | 2 +- .../hssf/record/formula/TestAreaErrPtg.java | 2 +- .../poi/hssf/record/formula/TestArrayPtg.java | 2 +- .../poi/hssf/record/formula/TestErrPtg.java | 2 +- .../formula/TestExternalFunctionFormulas.java | 2 +- .../record/formula/TestIntersectionPtg.java | 2 +- .../hssf/record/formula/TestPercentPtg.java | 6 +- .../poi/hssf/record/formula/TestRangePtg.java | 2 +- .../hssf/record/formula/TestReferencePtg.java | 30 +- .../poi/hssf/record/formula/TestUnionPtg.java | 2 +- .../formula/atp/TestYearFracCalculator.java | 66 ++++ ...TestYearFracCalculatorFromSpreadsheet.java | 178 +++++++++ .../function/TestReadMissingBuiltInFuncs.java | 2 +- .../poi/hssf/usermodel/TestCellStyle.java | 16 +- .../hssf/usermodel/TestDataValidation.java | 38 +- .../poi/hssf/usermodel/TestFormulas.java | 262 ++++++------- .../poi/hssf/usermodel/TestHSSFCell.java | 6 +- .../poi/hssf/usermodel/TestHSSFComment.java | 8 +- .../TestHSSFConditionalFormatting.java | 41 +++ .../poi/hssf/usermodel/TestHSSFDateUtil.java | 115 +++--- .../poi/hssf/usermodel/TestHSSFHyperlink.java | 34 +- .../poi/hssf/usermodel/TestHSSFOptimiser.java | 20 +- .../poi/hssf/usermodel/TestHSSFPalette.java | 10 +- .../poi/hssf/usermodel/TestHSSFRow.java | 62 ++-- .../poi/hssf/usermodel/TestHSSFSheet.java | 36 +- .../poi/hssf/usermodel/TestHSSFWorkbook.java | 8 +- .../hssf/usermodel/TestReadWriteChart.java | 6 +- .../poi/hssf/usermodel/TestSheetHiding.java | 8 +- .../hssf/usermodel/TestSheetShiftRows.java | 42 +-- .../hssf/usermodel/TestUnicodeWorkbook.java | 16 +- .../poi/hssf/usermodel/TestWorkbook.java | 20 +- 74 files changed, 2615 insertions(+), 667 deletions(-) create mode 100644 src/java/org/apache/poi/hssf/record/formula/atp/AnalysisToolPak.java create mode 100644 src/java/org/apache/poi/hssf/record/formula/atp/YearFrac.java create mode 100644 src/java/org/apache/poi/hssf/record/formula/atp/YearFracCalculator.java create mode 100644 src/java/org/apache/poi/hssf/record/formula/eval/NameXEval.java create mode 100644 src/scratchpad/src/org/apache/poi/hpbf/HPBFDocument.java create mode 100644 src/scratchpad/src/org/apache/poi/hpbf/extractor/PublisherTextExtractor.java create mode 100644 src/scratchpad/src/org/apache/poi/hpbf/model/EscherDelayStm.java create mode 100644 src/scratchpad/src/org/apache/poi/hpbf/model/EscherPart.java create mode 100644 src/scratchpad/src/org/apache/poi/hpbf/model/EscherStm.java create mode 100644 src/scratchpad/src/org/apache/poi/hpbf/model/HPBFPart.java create mode 100644 src/scratchpad/src/org/apache/poi/hpbf/model/MainContents.java create mode 100644 src/scratchpad/src/org/apache/poi/hpbf/model/QuillContents.java create mode 100644 src/scratchpad/src/org/apache/poi/hpbf/model/qcbits/QCBit.java create mode 100644 src/scratchpad/src/org/apache/poi/hpbf/model/qcbits/QCTextBit.java create mode 100644 src/scratchpad/src/org/apache/poi/hpbf/model/qcbits/UnknownQCBit.java create mode 100644 src/scratchpad/testcases/org/apache/poi/hpbf/TestHPBFDocument.java create mode 100755 src/scratchpad/testcases/org/apache/poi/hpbf/data/Simple.pub create mode 100644 src/scratchpad/testcases/org/apache/poi/hpbf/extractor/TextPublisherTextExtractor.java create mode 100644 src/scratchpad/testcases/org/apache/poi/hpbf/model/TestEscherParts.java create mode 100644 src/scratchpad/testcases/org/apache/poi/hpbf/model/TestQuillContents.java create mode 100644 src/testcases/org/apache/poi/hssf/data/ex45672.xls create mode 100644 src/testcases/org/apache/poi/hssf/data/yearfracExamples.xls create mode 100644 src/testcases/org/apache/poi/hssf/record/formula/atp/TestYearFracCalculator.java create mode 100644 src/testcases/org/apache/poi/hssf/record/formula/atp/TestYearFracCalculatorFromSpreadsheet.java diff --git a/src/contrib/src/org/apache/poi/hssf/usermodel/contrib/HSSFCellUtil.java b/src/contrib/src/org/apache/poi/hssf/usermodel/contrib/HSSFCellUtil.java index 67f4b38cb..8f40ab391 100644 --- a/src/contrib/src/org/apache/poi/hssf/usermodel/contrib/HSSFCellUtil.java +++ b/src/contrib/src/org/apache/poi/hssf/usermodel/contrib/HSSFCellUtil.java @@ -113,7 +113,7 @@ public final class HSSFCellUtil if ( cell == null ) { - cell = row.createCell( (short)column ); + cell = row.createCell(column ); } return cell; } diff --git a/src/documentation/content/xdocs/changes.xml b/src/documentation/content/xdocs/changes.xml index 62fee5b1c..bfc44a828 100644 --- a/src/documentation/content/xdocs/changes.xml +++ b/src/documentation/content/xdocs/changes.xml @@ -64,6 +64,9 @@ Created a common interface for handling Excel files, irrespective of if they are .xls or .xlsx + 45682 - Fix for cloning of CFRecordsAggregate + Initial support for evaluating external add-in functions like YEARFRAC + 45672 - Fix for MissingRecordAwareHSSFListener to prevent multiple LastCellOfRowDummyRecords when shared formulas are present 45645 - Fix for HSSFSheet.autoSizeColumn() for widths exceeding Short.MAX_VALUE 45623 - Support for additional HSSF header and footer fields, including bold and full file path 45623 - Support stripping HSSF header and footer fields (eg page number) out of header and footer text if required diff --git a/src/documentation/content/xdocs/status.xml b/src/documentation/content/xdocs/status.xml index 96272b165..5ed54a515 100644 --- a/src/documentation/content/xdocs/status.xml +++ b/src/documentation/content/xdocs/status.xml @@ -61,6 +61,9 @@ Created a common interface for handling Excel files, irrespective of if they are .xls or .xlsx + 45682 - Fix for cloning of CFRecordsAggregate + Initial support for evaluating external add-in functions like YEARFRAC + 45672 - Fix for MissingRecordAwareHSSFListener to prevent multiple LastCellOfRowDummyRecords when shared formulas are present 45645 - Fix for HSSFSheet.autoSizeColumn() for widths exceeding Short.MAX_VALUE 45623 - Support for additional HSSF header and footer fields, including bold and full file path 45623 - Support stripping HSSF header and footer fields (eg page number) out of header and footer text if required diff --git a/src/java/org/apache/poi/hssf/dev/HSSF.java b/src/java/org/apache/poi/hssf/dev/HSSF.java index 5297f0781..6583b94c6 100644 --- a/src/java/org/apache/poi/hssf/dev/HSSF.java +++ b/src/java/org/apache/poi/hssf/dev/HSSF.java @@ -132,7 +132,7 @@ public class HSSF { c.setCellStyle(cs); } - c = r.createCell(( short ) (cellnum + 1), + c = r.createCell(cellnum + 1, HSSFCell.CELL_TYPE_STRING); c.setCellValue(new HSSFRichTextString("TEST")); s.setColumnWidth(( short ) (cellnum + 1), @@ -347,7 +347,7 @@ public class HSSF sheet.removeRow(row); } HSSFRow row = sheet.getRow(39); - HSSFCell cell = row.getCell(( short ) 3); + HSSFCell cell = row.getCell(3); cell.setCellType(HSSFCell.CELL_TYPE_STRING); cell.setCellValue("MODIFIED CELL!!!!!"); diff --git a/src/java/org/apache/poi/hssf/eventusermodel/MissingRecordAwareHSSFListener.java b/src/java/org/apache/poi/hssf/eventusermodel/MissingRecordAwareHSSFListener.java index 0bdcb1d3d..e41b0b92a 100644 --- a/src/java/org/apache/poi/hssf/eventusermodel/MissingRecordAwareHSSFListener.java +++ b/src/java/org/apache/poi/hssf/eventusermodel/MissingRecordAwareHSSFListener.java @@ -17,22 +17,15 @@ package org.apache.poi.hssf.eventusermodel; -import org.apache.poi.hssf.eventusermodel.HSSFListener; import org.apache.poi.hssf.eventusermodel.dummyrecord.LastCellOfRowDummyRecord; import org.apache.poi.hssf.eventusermodel.dummyrecord.MissingCellDummyRecord; import org.apache.poi.hssf.eventusermodel.dummyrecord.MissingRowDummyRecord; import org.apache.poi.hssf.record.BOFRecord; -import org.apache.poi.hssf.record.BlankRecord; -import org.apache.poi.hssf.record.BoolErrRecord; -import org.apache.poi.hssf.record.BoundSheetRecord; -import org.apache.poi.hssf.record.FormulaRecord; -import org.apache.poi.hssf.record.LabelRecord; -import org.apache.poi.hssf.record.LabelSSTRecord; +import org.apache.poi.hssf.record.CellValueRecordInterface; import org.apache.poi.hssf.record.NoteRecord; -import org.apache.poi.hssf.record.NumberRecord; -import org.apache.poi.hssf.record.RKRecord; import org.apache.poi.hssf.record.Record; import org.apache.poi.hssf.record.RowRecord; +import org.apache.poi.hssf.record.SharedFormulaRecord; /** *

A HSSFListener which tracks rows and columns, and will @@ -44,16 +37,16 @@ import org.apache.poi.hssf.record.RowRecord; * file, or was skipped from being written as it was * blank. */ -public class MissingRecordAwareHSSFListener implements HSSFListener { +public final class MissingRecordAwareHSSFListener implements HSSFListener { private HSSFListener childListener; // Need to have different counters for cell rows and // row rows, as you sometimes get a RowRecord in the // middle of some cells, and that'd break everything - private int lastRowRow = -1; + private int lastRowRow; - private int lastCellRow = -1; - private int lastCellColumn = -1; + private int lastCellRow; + private int lastCellColumn; /** * Constructs a new MissingRecordAwareHSSFListener, which @@ -62,128 +55,80 @@ public class MissingRecordAwareHSSFListener implements HSSFListener { * @param listener The HSSFListener to pass records on to */ public MissingRecordAwareHSSFListener(HSSFListener listener) { + resetCounts(); childListener = listener; } public void processRecord(Record record) { - int thisRow = -1; - int thisColumn = -1; - - switch (record.getSid()) - { - // the BOFRecord can represent either the beginning of a sheet or the workbook - case BOFRecord.sid: - BOFRecord bof = (BOFRecord) record; - if (bof.getType() == bof.TYPE_WORKBOOK) - { - // Reset the row and column counts - new workbook - lastRowRow = -1; - lastCellRow = -1; - lastCellColumn = -1; - //System.out.println("Encountered workbook"); - } else if (bof.getType() == bof.TYPE_WORKSHEET) - { - // Reset the row and column counts - new sheet - lastRowRow = -1; - lastCellRow = -1; - lastCellColumn = -1; - //System.out.println("Encountered sheet reference"); - } - break; - case BoundSheetRecord.sid: - BoundSheetRecord bsr = (BoundSheetRecord) record; - //System.out.println("New sheet named: " + bsr.getSheetname()); - break; - case RowRecord.sid: - RowRecord rowrec = (RowRecord) record; - //System.out.println("Row " + rowrec.getRowNumber() + " found, first column at " - // + rowrec.getFirstCol() + " last column at " + rowrec.getLastCol()); - - // If there's a jump in rows, fire off missing row records - if(lastRowRow+1 < rowrec.getRowNumber()) { - for(int i=(lastRowRow+1); i -1) { for(int i=lastCellRow; inull. */ @@ -166,10 +126,16 @@ public final class CFRecordsAggregate extends Record { return (CFRuleRecord) rules.get(idx); } public void setRule(int idx, CFRuleRecord r) { + if (r == null) { + throw new IllegalArgumentException("r must not be null"); + } checkRuleIndex(idx); rules.set(idx, r); } public void addRule(CFRuleRecord r) { + if (r == null) { + throw new IllegalArgumentException("r must not be null"); + } if(rules.size() >= MAX_CONDTIONAL_FORMAT_RULES) { throw new IllegalStateException("Cannot have more than " + MAX_CONDTIONAL_FORMAT_RULES + " conditional format rules"); @@ -181,26 +147,6 @@ public final class CFRecordsAggregate extends Record { return rules.size(); } - /** - * @return sum of sizes of all aggregated records - */ - public int getRecordSize() - { - int size = 0; - if( header != null) - { - size += header.getRecordSize(); - } - if( rules != null) - { - for(Iterator irecs = rules.iterator(); irecs.hasNext(); ) - { - size += (( Record ) irecs.next()).getRecordSize(); - } - } - return size; - } - /** * String representation of CFRecordsAggregate */ @@ -216,12 +162,17 @@ public final class CFRecordsAggregate extends Record { for(int i=0; i @@ -53,7 +52,8 @@ public final class ConditionalFormattingTable extends RecordAggregate { public void visitContainedRecords(RecordVisitor rv) { for (int i = 0; i < _cfHeaders.size(); i++) { - rv.visitRecord((Record) _cfHeaders.get(i)); + CFRecordsAggregate subAgg = (CFRecordsAggregate) _cfHeaders.get(i); + subAgg.visitContainedRecords(rv); } } diff --git a/src/java/org/apache/poi/hssf/record/formula/NameXPtg.java b/src/java/org/apache/poi/hssf/record/formula/NameXPtg.java index b6076e1ea..393a8cd69 100644 --- a/src/java/org/apache/poi/hssf/record/formula/NameXPtg.java +++ b/src/java/org/apache/poi/hssf/record/formula/NameXPtg.java @@ -30,11 +30,11 @@ public final class NameXPtg extends OperandPtg { private final static int SIZE = 7; /** index to REF entry in externsheet record */ - private int _sheetRefIndex; + private final int _sheetRefIndex; /** index to defined name or externname table(1 based) */ - private int _nameNumber; + private final int _nameNumber; /** reserved must be 0 */ - private int _reserved; + private final int _reserved; private NameXPtg(int sheetRefIndex, int nameNumber, int reserved) { _sheetRefIndex = sheetRefIndex; @@ -73,4 +73,11 @@ public final class NameXPtg extends OperandPtg { public byte getDefaultOperandClass() { return Ptg.CLASS_VALUE; } + + public int getSheetRefIndex() { + return _sheetRefIndex; + } + public int getNameIndex() { + return _nameNumber - 1; + } } diff --git a/src/java/org/apache/poi/hssf/record/formula/atp/AnalysisToolPak.java b/src/java/org/apache/poi/hssf/record/formula/atp/AnalysisToolPak.java new file mode 100644 index 000000000..e5ec7fa83 --- /dev/null +++ b/src/java/org/apache/poi/hssf/record/formula/atp/AnalysisToolPak.java @@ -0,0 +1,154 @@ +/* ==================================================================== + 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 java.util.HashMap; +import java.util.Map; + +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.ValueEval; +import org.apache.poi.hssf.record.formula.functions.FreeRefFunction; +import org.apache.poi.ss.usermodel.Sheet; +import org.apache.poi.ss.usermodel.Workbook; + +public final class AnalysisToolPak { + + private static final FreeRefFunction NotImplemented = new FreeRefFunction() { + + public ValueEval evaluate(Eval[] args, int srcCellRow, short srcCellCol, + Workbook workbook, Sheet sheet) { + return ErrorEval.FUNCTION_NOT_IMPLEMENTED; + } + }; + + private static Map _functionsByName = createFunctionsMap(); + + private AnalysisToolPak() { + // no instances of this class + } + + public static FreeRefFunction findFunction(String name) { + return (FreeRefFunction)_functionsByName.get(name); + } + + private static Map createFunctionsMap() { + Map m = new HashMap(100); + + r(m, "ACCRINT", null); + r(m, "ACCRINTM", null); + r(m, "AMORDEGRC", null); + r(m, "AMORLINC", null); + r(m, "BESSELI", null); + r(m, "BESSELJ", null); + r(m, "BESSELK", null); + r(m, "BESSELY", null); + r(m, "BIN2DEC", null); + r(m, "BIN2HEX", null); + r(m, "BIN2OCT", null); + r(m, "CO MPLEX", null); + r(m, "CONVERT", null); + r(m, "COUPDAYBS", null); + r(m, "COUPDAYS", null); + r(m, "COUPDAYSNC", null); + r(m, "COUPNCD", null); + r(m, "COUPNUM", null); + r(m, "COUPPCD", null); + r(m, "CUMIPMT", null); + r(m, "CUMPRINC", null); + r(m, "DEC2BIN", null); + r(m, "DEC2HEX", null); + r(m, "DEC2OCT", null); + r(m, "DELTA", null); + r(m, "DISC", null); + r(m, "DOLLARDE", null); + r(m, "DOLLARFR", null); + r(m, "DURATION", null); + r(m, "EDATE", null); + r(m, "EFFECT", null); + r(m, "EOMONTH", null); + r(m, "ERF", null); + r(m, "ERFC", null); + r(m, "FACTDOUBLE", null); + r(m, "FVSCHEDULE", null); + r(m, "GCD", null); + r(m, "GESTEP", null); + r(m, "HEX2BIN", null); + r(m, "HEX2DEC", null); + r(m, "HEX2OCT", null); + r(m, "IMABS", null); + r(m, "IMAGINARY", null); + r(m, "IMARGUMENT", null); + r(m, "IMCONJUGATE", null); + r(m, "IMCOS", null); + r(m, "IMDIV", null); + r(m, "IMEXP", null); + r(m, "IMLN", null); + r(m, "IMLOG10", null); + r(m, "IMLOG2", null); + r(m, "IMPOWER", null); + r(m, "IMPRODUCT", null); + r(m, "IMREAL", null); + r(m, "IMSIN", null); + r(m, "IMSQRT", null); + r(m, "IMSUB", null); + r(m, "IMSUM", null); + r(m, "INTRATE", null); + r(m, "ISEVEN", null); + r(m, "ISODD", null); + r(m, "LCM", null); + r(m, "MDURATION", null); + r(m, "MROUND", null); + r(m, "MULTINOMIAL", null); + r(m, "NETWORKDAYS", null); + r(m, "NOMINAL", null); + r(m, "OCT2BIN", null); + r(m, "OCT2DEC", null); + r(m, "OCT2HEX", null); + r(m, "ODDFPRICE", null); + r(m, "ODDFYIELD", null); + r(m, "ODDLPRICE", null); + r(m, "ODDLYIELD", null); + r(m, "PRICE", null); + r(m, "PRICEDISC", null); + r(m, "PRICEMAT", null); + r(m, "QUOTIENT", null); + r(m, "RAND BETWEEN", null); + r(m, "RECEIVED", null); + r(m, "SERIESSUM", null); + r(m, "SQRTPI", null); + r(m, "TBILLEQ", null); + r(m, "TBILLPRICE", null); + r(m, "TBILLYIELD", null); + r(m, "WEEKNUM", null); + r(m, "WORKDAY", null); + r(m, "XIRR", null); + r(m, "XNPV", null); + r(m, "YEARFRAC", YearFrac.instance); + r(m, "YIELD", null); + r(m, "YIELDDISC", null); + r(m, "YIELDMAT", null); + + return m; + } + + private static void r(Map m, String functionName, FreeRefFunction pFunc) { + FreeRefFunction func = pFunc == null ? NotImplemented : pFunc; + m.put(functionName, func); + } +} diff --git a/src/java/org/apache/poi/hssf/record/formula/atp/YearFrac.java b/src/java/org/apache/poi/hssf/record/formula/atp/YearFrac.java new file mode 100644 index 000000000..517189d40 --- /dev/null +++ b/src/java/org/apache/poi/hssf/record/formula/atp/YearFrac.java @@ -0,0 +1,160 @@ +/* ==================================================================== + 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 java.util.Calendar; +import java.util.GregorianCalendar; +import java.util.regex.Pattern; + +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.NumberEval; +import org.apache.poi.hssf.record.formula.eval.OperandResolver; +import org.apache.poi.hssf.record.formula.eval.StringEval; +import org.apache.poi.hssf.record.formula.eval.ValueEval; +import org.apache.poi.hssf.record.formula.functions.FreeRefFunction; +import org.apache.poi.ss.usermodel.DateUtil; +import org.apache.poi.ss.usermodel.Sheet; +import org.apache.poi.ss.usermodel.Workbook; +/** + * Implementation of Excel 'Analysis ToolPak' function YEARFRAC()
+ * + * Returns the fraction of the year spanned by two dates.

+ * + * Syntax
+ * YEARFRAC(startDate, endDate, basis)

+ * + * The basis optionally specifies the behaviour of YEARFRAC as follows: + * + * + * + * + * + * + * + * + *
ValueDays per MonthDays per Year
0 (default)30360
1actualactual
2actual360
3actual365
430360
+ * + */ +final class YearFrac implements FreeRefFunction { + + public static final FreeRefFunction instance = new YearFrac(); + + private YearFrac() { + // enforce singleton + } + + public ValueEval evaluate(Eval[] args, int srcCellRow, short srcCellCol, Workbook workbook, + Sheet sheet) { + + double result; + try { + int basis = 0; // default + switch(args.length) { + case 3: + basis = evaluateIntArg(args[2], srcCellRow, srcCellCol); + case 2: + break; + default: + return ErrorEval.VALUE_INVALID; + } + double startDateVal = evaluateDateArg(args[0], srcCellRow, srcCellCol); + double endDateVal = evaluateDateArg(args[1], srcCellRow, srcCellCol); + result = YearFracCalculator.calculate(startDateVal, endDateVal, basis); + } catch (EvaluationException e) { + return e.getErrorEval(); + } + + return new NumberEval(result); + } + + private static double evaluateDateArg(Eval arg, int srcCellRow, short srcCellCol) throws EvaluationException { + ValueEval ve = OperandResolver.getSingleValue(arg, srcCellRow, srcCellCol); + + if (ve instanceof StringEval) { + String strVal = ((StringEval) ve).getStringValue(); + Double dVal = OperandResolver.parseDouble(strVal); + if (dVal != null) { + return dVal.doubleValue(); + } + Calendar date = parseDate(strVal); + return DateUtil.getExcelDate(date, false); + } + return OperandResolver.coerceValueToDouble(ve); + } + + private static Calendar parseDate(String strVal) throws EvaluationException { + String[] parts = Pattern.compile("/").split(strVal); + if (parts.length != 3) { + throw new EvaluationException(ErrorEval.VALUE_INVALID); + } + String part2 = parts[2]; + int spacePos = part2.indexOf(' '); + if (spacePos > 0) { + // drop time portion if present + part2 = part2.substring(0, spacePos); + } + int f0; + int f1; + int f2; + try { + f0 = Integer.parseInt(parts[0]); + f1 = Integer.parseInt(parts[1]); + f2 = Integer.parseInt(part2); + } catch (NumberFormatException e) { + throw new EvaluationException(ErrorEval.VALUE_INVALID); + } + 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); + } + + if (f0 >= 1900 && f0 < 9999) { + // when 4 digit value appears first, the format is YYYY/MM/DD, regardless of OS settings + return makeDate(f0, f1, f2); + } + // otherwise the format seems to depend on OS settings (default date format) + if (false) { + // MM/DD/YYYY is probably a good guess, if the in the US + return makeDate(f2, f0, f1); + } + // TODO - find a way to choose the correct date format + throw new RuntimeException("Unable to determine date format for text '" + strVal + "'"); + } + + /** + * @param month 1-based + */ + private static Calendar makeDate(int year, int month, int day) throws EvaluationException { + if (month < 1 || month > 12) { + throw new EvaluationException(ErrorEval.VALUE_INVALID); + } + Calendar cal = new GregorianCalendar(year, month-1, 1, 0, 0, 0); + cal.set(Calendar.MILLISECOND, 0); + if (day <1 || day>cal.getActualMaximum(Calendar.DAY_OF_MONTH)) { + throw new EvaluationException(ErrorEval.VALUE_INVALID); + } + return cal; + } + + private static int evaluateIntArg(Eval arg, int srcCellRow, short srcCellCol) throws EvaluationException { + ValueEval ve = OperandResolver.getSingleValue(arg, srcCellRow, srcCellCol); + return OperandResolver.coerceValueToInt(ve); + } +} diff --git a/src/java/org/apache/poi/hssf/record/formula/atp/YearFracCalculator.java b/src/java/org/apache/poi/hssf/record/formula/atp/YearFracCalculator.java new file mode 100644 index 000000000..40a5eb8db --- /dev/null +++ b/src/java/org/apache/poi/hssf/record/formula/atp/YearFracCalculator.java @@ -0,0 +1,344 @@ +/* ==================================================================== + 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 java.util.Calendar; +import java.util.GregorianCalendar; +import java.util.TimeZone; + +import org.apache.poi.hssf.record.formula.eval.ErrorEval; +import org.apache.poi.hssf.record.formula.eval.EvaluationException; +import org.apache.poi.hssf.usermodel.HSSFDateUtil; + + +/** + * Internal calculation methods for Excel 'Analysis ToolPak' function YEARFRAC()
+ * + * Algorithm inspired by www.dwheeler.com/yearfrac + * + * @author Josh Micich + */ +final class YearFracCalculator { + /** use UTC time-zone to avoid daylight savings issues */ + private static final TimeZone UTC_TIME_ZONE = TimeZone.getTimeZone("UTC"); + private static final int MS_PER_HOUR = 60 * 60 * 1000; + private static final int MS_PER_DAY = 24 * MS_PER_HOUR; + private static final int DAYS_PER_NORMAL_YEAR = 365; + private static final int DAYS_PER_LEAP_YEAR = DAYS_PER_NORMAL_YEAR + 1; + + /** the length of normal long months i.e. 31 */ + private static final int LONG_MONTH_LEN = 31; + /** the length of normal short months i.e. 30 */ + private static final int SHORT_MONTH_LEN = 30; + private static final int SHORT_FEB_LEN = 28; + private static final int LONG_FEB_LEN = SHORT_FEB_LEN + 1; + + private YearFracCalculator() { + // no instances of this class + } + + + public static double calculate(double pStartDateVal, double pEndDateVal, int basis) throws EvaluationException { + + if (basis < 0 || basis >= 5) { + // if basis is invalid the result is #NUM! + throw new EvaluationException(ErrorEval.NUM_ERROR); + } + + // common logic for all bases + + // truncate day values + int startDateVal = (int) Math.floor(pStartDateVal); + int endDateVal = (int) Math.floor(pEndDateVal); + if (startDateVal == endDateVal) { + // when dates are equal, result is zero + return 0; + } + // swap start and end if out of order + if (startDateVal > endDateVal) { + int temp = startDateVal; + startDateVal = endDateVal; + endDateVal = temp; + } + + switch (basis) { + case 0: return basis0(startDateVal, endDateVal); + case 1: return basis1(startDateVal, endDateVal); + case 2: return basis2(startDateVal, endDateVal); + case 3: return basis3(startDateVal, endDateVal); + case 4: return basis4(startDateVal, endDateVal); + } + throw new IllegalStateException("cannot happen"); + } + + + /** + * @param startDateVal assumed to be less than or equal to endDateVal + * @param endDateVal assumed to be greater than or equal to startDateVal + */ + public static double basis0(int startDateVal, int endDateVal) { + SimpleDate startDate = createDate(startDateVal); + SimpleDate endDate = createDate(endDateVal); + int date1day = startDate.day; + int date2day = endDate.day; + + // basis zero has funny adjustments to the day-of-month fields when at end-of-month + if (date1day == LONG_MONTH_LEN && date2day == LONG_MONTH_LEN) { + date1day = SHORT_MONTH_LEN; + date2day = SHORT_MONTH_LEN; + } else if (date1day == LONG_MONTH_LEN) { + date1day = SHORT_MONTH_LEN; + } else if (date1day == SHORT_MONTH_LEN && date2day == LONG_MONTH_LEN) { + date2day = SHORT_MONTH_LEN; + // Note: If date2day==31, it STAYS 31 if date1day < 30. + // Special fixes for February: + } else if (startDate.month == 2 && isLastDayOfMonth(startDate)) { + // Note - these assignments deliberately set Feb 30 date. + date1day = SHORT_MONTH_LEN; + if (endDate.month == 2 && isLastDayOfMonth(endDate)) { + // only adjusted when first date is last day in Feb + date2day = SHORT_MONTH_LEN; + } + } + return calculateAdjusted(startDate, endDate, date1day, date2day); + } + /** + * @param startDateVal assumed to be less than or equal to endDateVal + * @param endDateVal assumed to be greater than or equal to startDateVal + */ + public static double basis1(int startDateVal, int endDateVal) { + SimpleDate startDate = createDate(startDateVal); + SimpleDate endDate = createDate(endDateVal); + double yearLength; + if (isGreaterThanOneYear(startDate, endDate)) { + yearLength = averageYearLength(startDate.year, endDate.year); + } else if (shouldCountFeb29(startDate, endDate)) { + yearLength = DAYS_PER_LEAP_YEAR; + } else { + yearLength = DAYS_PER_NORMAL_YEAR; + } + return dateDiff(startDate.tsMilliseconds, endDate.tsMilliseconds) / yearLength; + } + + /** + * @param startDateVal assumed to be less than or equal to endDateVal + * @param endDateVal assumed to be greater than or equal to startDateVal + */ + public static double basis2(int startDateVal, int endDateVal) { + return (endDateVal - startDateVal) / 360.0; + } + /** + * @param startDateVal assumed to be less than or equal to endDateVal + * @param endDateVal assumed to be greater than or equal to startDateVal + */ + public static double basis3(double startDateVal, double endDateVal) { + return (endDateVal - startDateVal) / 365.0; + } + /** + * @param startDateVal assumed to be less than or equal to endDateVal + * @param endDateVal assumed to be greater than or equal to startDateVal + */ + public static double basis4(int startDateVal, int endDateVal) { + SimpleDate startDate = createDate(startDateVal); + SimpleDate endDate = createDate(endDateVal); + int date1day = startDate.day; + int date2day = endDate.day; + + + // basis four has funny adjustments to the day-of-month fields when at end-of-month + if (date1day == LONG_MONTH_LEN) { + date1day = SHORT_MONTH_LEN; + } + if (date2day == LONG_MONTH_LEN) { + date2day = SHORT_MONTH_LEN; + } + // Note - no adjustments for end of Feb + return calculateAdjusted(startDate, endDate, date1day, date2day); + } + + + private static double calculateAdjusted(SimpleDate startDate, SimpleDate endDate, int date1day, + int date2day) { + double dayCount + = (endDate.year - startDate.year) * 360 + + (endDate.month - startDate.month) * SHORT_MONTH_LEN + + (date2day - date1day) * 1; + return dayCount / 360; + } + + private static boolean isLastDayOfMonth(SimpleDate date) { + if (date.day < SHORT_FEB_LEN) { + return false; + } + return date.day == getLastDayOfMonth(date); + } + + private static int getLastDayOfMonth(SimpleDate date) { + switch (date.month) { + case 1: + case 3: + case 5: + case 7: + case 8: + case 10: + case 12: + return LONG_MONTH_LEN; + case 4: + case 6: + case 9: + case 11: + return SHORT_MONTH_LEN; + } + if (isLeapYear(date.year)) { + return LONG_FEB_LEN; + } + return SHORT_FEB_LEN; + } + + /** + * Assumes dates are no more than 1 year apart. + * @return true if dates both within a leap year, or span a period including Feb 29 + */ + private static boolean shouldCountFeb29(SimpleDate start, SimpleDate end) { + boolean startIsLeapYear = isLeapYear(start.year); + if (startIsLeapYear && start.year == end.year) { + // note - dates may not actually span Feb-29, but it gets counted anyway in this case + return true; + } + + boolean endIsLeapYear = isLeapYear(end.year); + if (!startIsLeapYear && !endIsLeapYear) { + return false; + } + if (startIsLeapYear) { + switch (start.month) { + case SimpleDate.JANUARY: + case SimpleDate.FEBRUARY: + return true; + } + return false; + } + if (endIsLeapYear) { + switch (end.month) { + case SimpleDate.JANUARY: + return false; + case SimpleDate.FEBRUARY: + break; + default: + return true; + } + return end.day == LONG_FEB_LEN; + } + return false; + } + + /** + * @return the whole number of days between the two time-stamps. Both time-stamps are + * assumed to represent 12:00 midnight on the respective day. + */ + private static int dateDiff(long startDateMS, long endDateMS) { + long msDiff = endDateMS - startDateMS; + + // some extra checks to make sure we don't hide some other bug with the rounding + int remainderHours = (int) ((msDiff % MS_PER_DAY) / MS_PER_HOUR); + switch (remainderHours) { + case 0: // normal case + break; + case 1: // transition from normal time to daylight savings adjusted + case 23: // transition from daylight savings adjusted to normal time + // Unexpected since we are using UTC_TIME_ZONE + default: + throw new RuntimeException("Unexpected date diff between " + startDateMS + " and " + endDateMS); + + } + return (int) (0.5 + ((double)msDiff / MS_PER_DAY)); + } + + private static double averageYearLength(int startYear, int endYear) { + int dayCount = 0; + for (int i=startYear; i<=endYear; i++) { + dayCount += DAYS_PER_NORMAL_YEAR; + if (isLeapYear(i)) { + dayCount++; + } + } + double numberOfYears = endYear-startYear+1; + return dayCount / numberOfYears; + } + + private static boolean isLeapYear(int i) { + // leap years are always divisible by 4 + if (i % 4 != 0) { + return false; + } + // each 4th century is a leap year + if (i % 400 == 0) { + return true; + } + // all other centuries are *not* leap years + if (i % 100 == 0) { + return false; + } + return true; + } + + private static boolean isGreaterThanOneYear(SimpleDate start, SimpleDate end) { + if (start.year == end.year) { + return false; + } + if (start.year + 1 != end.year) { + return true; + } + + if (start.month > end.month) { + return false; + } + if (start.month < end.month) { + return true; + } + + return start.day < end.day; + } + + private static SimpleDate createDate(int dayCount) { + GregorianCalendar calendar = new GregorianCalendar(UTC_TIME_ZONE); + HSSFDateUtil.setCalendar(calendar, dayCount, 0, false); + return new SimpleDate(calendar); + } + + private static final class SimpleDate { + + public static final int JANUARY = 1; + public static final int FEBRUARY = 2; + + public final int year; + /** 1-based month */ + public final int month; + /** day of month */ + public final int day; + /** milliseconds since 1970 */ + public long tsMilliseconds; + + public SimpleDate(Calendar cal) { + year = cal.get(Calendar.YEAR); + month = cal.get(Calendar.MONTH) + 1; + day = cal.get(Calendar.DAY_OF_MONTH); + tsMilliseconds = cal.getTimeInMillis(); + } + } +} diff --git a/src/java/org/apache/poi/hssf/record/formula/eval/ExternalFunction.java b/src/java/org/apache/poi/hssf/record/formula/eval/ExternalFunction.java index f40c83202..ffaf780ab 100755 --- a/src/java/org/apache/poi/hssf/record/formula/eval/ExternalFunction.java +++ b/src/java/org/apache/poi/hssf/record/formula/eval/ExternalFunction.java @@ -17,14 +17,16 @@ package org.apache.poi.hssf.record.formula.eval; +import org.apache.poi.hssf.record.formula.atp.AnalysisToolPak; import org.apache.poi.hssf.record.formula.functions.FreeRefFunction; import org.apache.poi.ss.usermodel.Sheet; import org.apache.poi.ss.usermodel.Workbook; /** * - * Common entry point for all external functions (where + * Common entry point for all user-defined (non-built-in) functions (where * AbstractFunctionPtg.field_2_fnc_index == 255) * + * TODO rename to UserDefinedFunction * @author Josh Micich */ final class ExternalFunction implements FreeRefFunction { @@ -36,27 +38,43 @@ final class ExternalFunction implements FreeRefFunction { throw new RuntimeException("function name argument missing"); } - if (!(args[0] instanceof NameEval)) { - throw new RuntimeException("First argument should be a NameEval, but got (" - + args[0].getClass().getName() + ")"); - } - NameEval functionNameEval = (NameEval) args[0]; - - int nOutGoingArgs = nIncomingArgs -1; - Eval[] outGoingArgs = new Eval[nOutGoingArgs]; - System.arraycopy(args, 1, outGoingArgs, 0, nOutGoingArgs); - + Eval nameArg = args[0]; FreeRefFunction targetFunc; try { - targetFunc = findTargetFunction(workbook, functionNameEval); + if (nameArg instanceof NameEval) { + targetFunc = findInternalUserDefinedFunction(workbook, (NameEval) nameArg); + } else if (nameArg instanceof NameXEval) { + targetFunc = findExternalUserDefinedFunction(workbook, (NameXEval) nameArg); + } else { + throw new RuntimeException("First argument should be a NameEval, but got (" + + nameArg.getClass().getName() + ")"); + } } catch (EvaluationException e) { return e.getErrorEval(); } - + int nOutGoingArgs = nIncomingArgs -1; + Eval[] outGoingArgs = new Eval[nOutGoingArgs]; + System.arraycopy(args, 1, outGoingArgs, 0, nOutGoingArgs); return targetFunc.evaluate(outGoingArgs, srcCellRow, srcCellCol, workbook, sheet); } - private FreeRefFunction findTargetFunction(Workbook workbook, NameEval functionNameEval) throws EvaluationException { + private FreeRefFunction findExternalUserDefinedFunction(Workbook workbook, + NameXEval n) throws EvaluationException { + String functionName = workbook.resolveNameXText(n.getSheetRefIndex(), n.getNameNumber()); + + if(false) { + System.out.println("received call to external user defined function (" + functionName + ")"); + } + // currently only looking for functions from the 'Analysis TookPak' + // 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) { + return result; + } + throw new EvaluationException(ErrorEval.FUNCTION_NOT_IMPLEMENTED); + } + + private FreeRefFunction findInternalUserDefinedFunction(Workbook workbook, NameEval functionNameEval) throws EvaluationException { int numberOfNames = workbook.getNumberOfNames(); @@ -68,7 +86,7 @@ final class ExternalFunction implements FreeRefFunction { String functionName = workbook.getNameName(nameIndex); if(false) { - System.out.println("received call to external function index (" + functionName + ")"); + 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 @@ -77,5 +95,5 @@ final class ExternalFunction implements FreeRefFunction { throw new EvaluationException(ErrorEval.FUNCTION_NOT_IMPLEMENTED); } - } + diff --git a/src/java/org/apache/poi/hssf/record/formula/eval/NameXEval.java b/src/java/org/apache/poi/hssf/record/formula/eval/NameXEval.java new file mode 100644 index 000000000..12b6be380 --- /dev/null +++ b/src/java/org/apache/poi/hssf/record/formula/eval/NameXEval.java @@ -0,0 +1,49 @@ +/* ==================================================================== + 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 + */ +public final class NameXEval implements Eval { + + /** index to REF entry in externsheet record */ + private final int _sheetRefIndex; + /** index to defined name or externname table(1 based) */ + private final int _nameNumber; + + public NameXEval(int sheetRefIndex, int nameNumber) { + _sheetRefIndex = sheetRefIndex; + _nameNumber = nameNumber; + } + + public int getSheetRefIndex() { + return _sheetRefIndex; + } + public int getNameNumber() { + return _nameNumber; + } + + public String toString() { + StringBuffer sb = new StringBuffer(64); + sb.append(getClass().getName()).append(" ["); + sb.append(_sheetRefIndex).append(", ").append(_nameNumber); + sb.append("]"); + return sb.toString(); + } +} diff --git a/src/java/org/apache/poi/hssf/usermodel/HSSFConditionalFormattingRule.java b/src/java/org/apache/poi/hssf/usermodel/HSSFConditionalFormattingRule.java index 10d86015a..fc34b9da9 100644 --- a/src/java/org/apache/poi/hssf/usermodel/HSSFConditionalFormattingRule.java +++ b/src/java/org/apache/poi/hssf/usermodel/HSSFConditionalFormattingRule.java @@ -41,6 +41,12 @@ public final class HSSFConditionalFormattingRule private final HSSFWorkbook workbook; HSSFConditionalFormattingRule(HSSFWorkbook pWorkbook, CFRuleRecord pRuleRecord) { + if (pWorkbook == null) { + throw new IllegalArgumentException("pWorkbook must not be null"); + } + if (pRuleRecord == null) { + throw new IllegalArgumentException("pRuleRecord must not be null"); + } workbook = pWorkbook; cfRuleRecord = pRuleRecord; } diff --git a/src/java/org/apache/poi/hssf/usermodel/HSSFRow.java b/src/java/org/apache/poi/hssf/usermodel/HSSFRow.java index dff82a732..4e351e6ad 100644 --- a/src/java/org/apache/poi/hssf/usermodel/HSSFRow.java +++ b/src/java/org/apache/poi/hssf/usermodel/HSSFRow.java @@ -349,7 +349,7 @@ public final class HSSFRow implements Comparable, Row { } if(policy == CREATE_NULL_AS_BLANK) { if(cell == null) { - return createCell((short)cellnum, HSSFCell.CELL_TYPE_BLANK); + return createCell(cellnum, HSSFCell.CELL_TYPE_BLANK); } return cell; } diff --git a/src/java/org/apache/poi/hssf/usermodel/HSSFSheet.java b/src/java/org/apache/poi/hssf/usermodel/HSSFSheet.java index 3e51fe831..280284439 100644 --- a/src/java/org/apache/poi/hssf/usermodel/HSSFSheet.java +++ b/src/java/org/apache/poi/hssf/usermodel/HSSFSheet.java @@ -1836,7 +1836,7 @@ public class HSSFSheet implements org.apache.poi.ss.usermodel.Sheet // new HSSFComment instances, which is bad HSSFRow r = getRow(row); if(r != null) { - HSSFCell c = r.getCell((short)column); + HSSFCell c = r.getCell(column); if(c != null) { return c.getCellComment(); } else { diff --git a/src/java/org/apache/poi/ss/usermodel/DateUtil.java b/src/java/org/apache/poi/ss/usermodel/DateUtil.java index 002b4aedc..d45748909 100644 --- a/src/java/org/apache/poi/ss/usermodel/DateUtil.java +++ b/src/java/org/apache/poi/ss/usermodel/DateUtil.java @@ -158,9 +158,16 @@ public class DateUtil { if (!isValidExcelDate(date)) { return null; } + int wholeDays = (int)Math.floor(date); + int millisecondsInDay = (int)((date - wholeDays) * DAY_MILLISECONDS + 0.5); + Calendar calendar = new GregorianCalendar(); // using default time-zone + setCalendar(calendar, wholeDays, millisecondsInDay, use1904windowing); + return calendar.getTime(); + } + public static void setCalendar(Calendar calendar, int wholeDays, + int millisecondsInDay, boolean use1904windowing) { int startYear = 1900; int dayAdjust = -1; // Excel thinks 2/29/1900 is a valid date, which it isn't - int wholeDays = (int)Math.floor(date); if (use1904windowing) { startYear = 1904; dayAdjust = 1; // 1904 date windowing uses 1/2/1904 as the first day @@ -170,12 +177,8 @@ public class DateUtil { // If Excel date == 2/29/1900, will become 3/1/1900 in Java representation dayAdjust = 0; } - GregorianCalendar calendar = new GregorianCalendar(startYear,0, - wholeDays + dayAdjust); - int millisecondsInDay = (int)((date - Math.floor(date)) * - DAY_MILLISECONDS + 0.5); + calendar.set(startYear,0, wholeDays + dayAdjust, 0, 0, 0); calendar.set(GregorianCalendar.MILLISECOND, millisecondsInDay); - return calendar.getTime(); } /** diff --git a/src/java/org/apache/poi/ss/usermodel/FormulaEvaluator.java b/src/java/org/apache/poi/ss/usermodel/FormulaEvaluator.java index 22321ff9e..9cd7f918e 100644 --- a/src/java/org/apache/poi/ss/usermodel/FormulaEvaluator.java +++ b/src/java/org/apache/poi/ss/usermodel/FormulaEvaluator.java @@ -50,6 +50,7 @@ import org.apache.poi.hssf.record.formula.eval.ErrorEval; import org.apache.poi.hssf.record.formula.eval.Eval; import org.apache.poi.hssf.record.formula.eval.FunctionEval; import org.apache.poi.hssf.record.formula.eval.NameEval; +import org.apache.poi.hssf.record.formula.eval.NameXEval; import org.apache.poi.hssf.record.formula.eval.NumberEval; import org.apache.poi.hssf.record.formula.eval.OperationEval; import org.apache.poi.hssf.record.formula.eval.Ref2DEval; @@ -348,7 +349,8 @@ public class FormulaEvaluator { continue; } if (ptg instanceof NameXPtg) { - // TODO - external functions + NameXPtg nameXPtg = (NameXPtg) ptg; + stack.push(new NameXEval(nameXPtg.getSheetRefIndex(), nameXPtg.getNameIndex())); continue; } if (ptg instanceof UnknownPtg) { continue; } diff --git a/src/scratchpad/src/org/apache/poi/hpbf/HPBFDocument.java b/src/scratchpad/src/org/apache/poi/hpbf/HPBFDocument.java new file mode 100644 index 000000000..49de0d087 --- /dev/null +++ b/src/scratchpad/src/org/apache/poi/hpbf/HPBFDocument.java @@ -0,0 +1,86 @@ +/* ==================================================================== + 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.hpbf; + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; + +import org.apache.poi.POIDocument; +import org.apache.poi.hpbf.model.EscherDelayStm; +import org.apache.poi.hpbf.model.EscherStm; +import org.apache.poi.hpbf.model.MainContents; +import org.apache.poi.hpbf.model.QuillContents; +import org.apache.poi.poifs.filesystem.DirectoryNode; +import org.apache.poi.poifs.filesystem.POIFSFileSystem; + +/** + * This class provides the basic functionality + * for HPBF, our implementation of the publisher + * file format. + */ +public final class HPBFDocument extends POIDocument { + private MainContents mainContents; + private QuillContents quillContents; + private EscherStm escherStm; + private EscherDelayStm escherDelayStm; + + /** + * Opens a new publisher document + */ + public HPBFDocument(POIFSFileSystem fs) throws IOException { + this(fs.getRoot(), fs); + } + public HPBFDocument(InputStream inp) throws IOException { + this(new POIFSFileSystem(inp)); + } + + /** + * Opens an embeded publisher document, + * at the given directory. + */ + public HPBFDocument(DirectoryNode dir, POIFSFileSystem fs) throws IOException { + super(dir, fs); + + // Go looking for our interesting child + // streams + mainContents = new MainContents(dir); + quillContents = new QuillContents(dir); + + // Now the Escher bits + escherStm = new EscherStm(dir); + escherDelayStm = new EscherDelayStm(dir); + } + + public MainContents getMainContents() { + return mainContents; + } + public QuillContents getQuillContents() { + return quillContents; + } + public EscherStm getEscherStm() { + return escherStm; + } + public EscherDelayStm getEscherDelayStm() { + return escherDelayStm; + } + + public void write(OutputStream out) throws IOException { + throw new IllegalStateException("Writing is not yet implemented, see http://poi.apache.org/hpbf/"); + } +} diff --git a/src/scratchpad/src/org/apache/poi/hpbf/extractor/PublisherTextExtractor.java b/src/scratchpad/src/org/apache/poi/hpbf/extractor/PublisherTextExtractor.java new file mode 100644 index 000000000..2257283a0 --- /dev/null +++ b/src/scratchpad/src/org/apache/poi/hpbf/extractor/PublisherTextExtractor.java @@ -0,0 +1,78 @@ +/* ==================================================================== + 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.hpbf.extractor; + +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; + +import org.apache.poi.POIOLE2TextExtractor; +import org.apache.poi.hpbf.HPBFDocument; +import org.apache.poi.hpbf.model.qcbits.QCBit; +import org.apache.poi.hpbf.model.qcbits.QCTextBit; +import org.apache.poi.poifs.filesystem.POIFSFileSystem; + +/** + * Extract text from HPBF Publisher files + */ +public class PublisherTextExtractor extends POIOLE2TextExtractor { + private HPBFDocument doc; + + public PublisherTextExtractor(HPBFDocument doc) { + super(doc); + this.doc = doc; + } + public PublisherTextExtractor(POIFSFileSystem fs) throws IOException { + this(new HPBFDocument(fs)); + } + public PublisherTextExtractor(InputStream is) throws IOException { + this(new POIFSFileSystem(is)); + } + + public String getText() { + StringBuffer text = new StringBuffer(); + + // Get the text from the Quill Contents + QCBit[] bits = doc.getQuillContents().getBits(); + for(int i=0; i"); + } + + for(int i=0; i 0) { + EscherRecord er = erf.createRecord(data, 0); + er.fillFields(data, 0, erf); + left -= er.getRecordSize(); + + ec.add(er); + } + + records = (EscherRecord[]) + ec.toArray(new EscherRecord[ec.size()]); + } + + public EscherRecord[] getEscherRecords() { + return records; + } + + /** + * Serialises our Escher children back + * into bytes. + */ + protected void generateData() { + int size = 0; + for(int i=0; i QuillSub -> CONTENTS + */ +public final class QuillContents extends HPBFPart { + private static final String[] PATH = { "Quill", "QuillSub", "CONTENTS", }; + private QCBit[] bits; + + public QuillContents(DirectoryNode baseDir) throws IOException { + super(baseDir, PATH); + + // Now parse the first 512 bytes, and produce + // all our bits + + // Check first 8 bytes + String f8 = new String(data, 0, 8); + if(! f8.equals("CHNKINK ")) { + throw new IllegalArgumentException("Expecting 'CHNKINK ' but was '"+f8+"'"); + } + // Ignore the next 24, for now at least + + // Now, parse all our QC Bits + bits = new QCBit[20]; + for(int i=0; i<20; i++) { + int offset = 0x20 + i*24; + if(data[offset] == 0x18 && data[offset+1] == 0x00) { + // Has some data + String thingType = new String(data, offset+2, 4); + int optA = LittleEndian.getUShort(data, offset+6); + int optB = LittleEndian.getUShort(data, offset+8); + int optC = LittleEndian.getUShort(data, offset+10); + String bitType = new String(data, offset+12, 4); + int from = (int)LittleEndian.getUInt(data, offset+16); + int len = (int)LittleEndian.getUInt(data, offset+20); + + byte[] bitData = new byte[len]; + System.arraycopy(data, from, bitData, 0, len); + + // Create + if(bitType.equals("TEXT")) { + bits[i] = new QCTextBit(thingType, bitType, bitData); + } else { + bits[i] = new UnknownQCBit(thingType, bitType, bitData); + } + bits[i].setOptA(optA); + bits[i].setOptB(optB); + bits[i].setOptC(optC); + } else { + // Doesn't have data + } + } + } + + public QCBit[] getBits() { + return bits; + } + + protected void generateData() { + // TODO + throw new IllegalStateException("Not done yet!"); + } +} diff --git a/src/scratchpad/src/org/apache/poi/hpbf/model/qcbits/QCBit.java b/src/scratchpad/src/org/apache/poi/hpbf/model/qcbits/QCBit.java new file mode 100644 index 000000000..61c7955f6 --- /dev/null +++ b/src/scratchpad/src/org/apache/poi/hpbf/model/qcbits/QCBit.java @@ -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.hpbf.model.qcbits; + +/** + * Parent of all Quill CONTENTS bits + */ +public abstract class QCBit { + protected String thingType; + protected String bitType; + protected byte[] data; + + protected int optA; + protected int optB; + protected int optC; + + public QCBit(String thingType, String bitType, byte[] data) { + this.thingType = thingType; + this.bitType = bitType; + this.data = data; + } + + /** + * Returns the type of the thing, eg TEXT, FONT + * or TOKN + */ + public String getThingType() { return thingType; } + /** + * Returns the type of the bit data, eg TEXT + * or PLC + */ + public String getBitType() { return bitType; } + public byte[] getData() { return data; } + + public int getOptA() { + return optA; + } + public void setOptA(int optA) { + this.optA = optA; + } + + public int getOptB() { + return optB; + } + public void setOptB(int optB) { + this.optB = optB; + } + + public int getOptC() { + return optC; + } + public void setOptC(int optC) { + this.optC = optC; + } +} diff --git a/src/scratchpad/src/org/apache/poi/hpbf/model/qcbits/QCTextBit.java b/src/scratchpad/src/org/apache/poi/hpbf/model/qcbits/QCTextBit.java new file mode 100644 index 000000000..e3c8dcb58 --- /dev/null +++ b/src/scratchpad/src/org/apache/poi/hpbf/model/qcbits/QCTextBit.java @@ -0,0 +1,43 @@ +/* ==================================================================== + 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.hpbf.model.qcbits; + +import org.apache.poi.util.StringUtil; + +/** + * A Text based bit of Quill Contents + */ +public class QCTextBit extends QCBit { + public QCTextBit(String thingType, String bitType, byte[] data) { + super(thingType, bitType, data); + } + + /** + * Returns the text. Note that line endings + * are \r and not \n + */ + public String getText() { + return StringUtil.getFromUnicodeLE( + data, 0, data.length/2 + ); + } + + public void setText(String text) { + data = new byte[text.length()*2]; + StringUtil.putUnicodeLE(text, data, 0); + } +} diff --git a/src/scratchpad/src/org/apache/poi/hpbf/model/qcbits/UnknownQCBit.java b/src/scratchpad/src/org/apache/poi/hpbf/model/qcbits/UnknownQCBit.java new file mode 100644 index 000000000..2548b4fca --- /dev/null +++ b/src/scratchpad/src/org/apache/poi/hpbf/model/qcbits/UnknownQCBit.java @@ -0,0 +1,27 @@ +/* ==================================================================== + 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.hpbf.model.qcbits; + +/** + * Any Quill Contents bits we don't know + * how to handle explicitly + */ +public class UnknownQCBit extends QCBit { + public UnknownQCBit(String thingType, String bitType, byte[] data) { + super(thingType, bitType, data); + } +} diff --git a/src/scratchpad/testcases/org/apache/poi/hpbf/TestHPBFDocument.java b/src/scratchpad/testcases/org/apache/poi/hpbf/TestHPBFDocument.java new file mode 100644 index 000000000..c0186dd8d --- /dev/null +++ b/src/scratchpad/testcases/org/apache/poi/hpbf/TestHPBFDocument.java @@ -0,0 +1,60 @@ +/* ==================================================================== + 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.hpbf; + +import java.io.File; +import java.io.FileInputStream; + +import junit.framework.TestCase; + +public class TestHPBFDocument extends TestCase { + private String dir; + + protected void setUp() throws Exception { + dir = System.getProperty("HPBF.testdata.path"); + } + + public void testOpen() throws Exception { + File f = new File(dir, "Sample.pub"); + HPBFDocument doc = new HPBFDocument( + new FileInputStream(f) + ); + + assertNotNull(doc); + } + + public void testBits() throws Exception { + File f = new File(dir, "Sample.pub"); + HPBFDocument doc = new HPBFDocument( + new FileInputStream(f) + ); + + assertNotNull(doc.getMainContents()); + assertNotNull(doc.getQuillContents()); + assertNotNull(doc.getEscherStm()); + assertNotNull(doc.getEscherDelayStm()); + + assertTrue(doc.getMainContents().getData().length > 0); + assertTrue(doc.getQuillContents().getData().length > 0); + assertTrue(doc.getEscherStm().getData().length > 0); + assertTrue(doc.getEscherDelayStm().getData().length == 0); + } + + // TODO +// public void testWrite() throws Exception { +// } +} diff --git a/src/scratchpad/testcases/org/apache/poi/hpbf/data/Simple.pub b/src/scratchpad/testcases/org/apache/poi/hpbf/data/Simple.pub new file mode 100755 index 0000000000000000000000000000000000000000..2397b9d01cfa159de2f73cf5c990d9698eb69567 GIT binary patch literal 65536 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 D*Z@mO literal 0 HcmV?d00001 diff --git a/src/testcases/org/apache/poi/hssf/data/yearfracExamples.xls b/src/testcases/org/apache/poi/hssf/data/yearfracExamples.xls new file mode 100644 index 0000000000000000000000000000000000000000..2b2be7d7d87d090ed3dc202e7daf2739050b13c1 GIT binary patch literal 29184 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 wH5~1=t5^5h#<}DfW6RX! 100); + } public void openNormal() { - HSSFRequest req = new HSSFRequest(); - MockHSSFListener mockListen = new MockHSSFListener(); - MissingRecordAwareHSSFListener listener = new MissingRecordAwareHSSFListener(mockListen); - req.addListenerForAllRecords(listener); - - HSSFEventFactory factory = new HSSFEventFactory(); - try { - InputStream is = HSSFTestDataSamples.openSampleFileStream("MissingBits.xls"); - POIFSFileSystem fs = new POIFSFileSystem(is); - factory.processWorkbookEvents(req, fs); - } catch (IOException e) { - throw new RuntimeException(e); - } - - r = mockListen.getRecords(); - assertTrue(r.length > 100); - } - public void openAlt() { - HSSFRequest req = new HSSFRequest(); - MockHSSFListener mockListen = new MockHSSFListener(); - MissingRecordAwareHSSFListener listener = new MissingRecordAwareHSSFListener(mockListen); - req.addListenerForAllRecords(listener); - - HSSFEventFactory factory = new HSSFEventFactory(); - try { - InputStream is = HSSFTestDataSamples.openSampleFileStream("MRExtraLines.xls"); - POIFSFileSystem fs = new POIFSFileSystem(is); - factory.processWorkbookEvents(req, fs); - } catch (IOException e) { - throw new RuntimeException(e); - } - - r = mockListen.getRecords(); - assertTrue(r.length > 100); - } + readRecords("MissingBits.xls"); + } - public void testMissingRowRecords() throws Exception { + public void testMissingRowRecords() { openNormal(); // We have rows 0, 1, 2, 20 and 21 @@ -126,7 +113,7 @@ public final class TestMissingRecordAwareHSSFListener extends TestCase { assertEquals(19, mr.getRowNumber()); } - public void testEndOfRowRecords() throws Exception { + public void testEndOfRowRecords() { openNormal(); // Find the cell at 0,0 @@ -248,7 +235,7 @@ public final class TestMissingRecordAwareHSSFListener extends TestCase { } - public void testMissingCellRecords() throws Exception { + public void testMissingCellRecords() { openNormal(); // Find the cell at 0,0 @@ -350,29 +337,21 @@ public final class TestMissingRecordAwareHSSFListener extends TestCase { // Make sure we don't put in any extra new lines // that aren't already there - public void testNoExtraNewLines() throws Exception { + public void testNoExtraNewLines() { // Load a different file - openAlt(); - - // This file has has something in lines 1-33 - List lcor = new ArrayList(); + readRecords("MRExtraLines.xls"); + + int rowCount=0; for(int i=0; i 0.000000001) { + double hours = diff * 365 * 24; + System.out.println(startDate + " " + endDate + " off by " + hours + " hours"); + assertEquals(expectedValue, actualValue, 0.000000001); + } + + } + + private static double md(int year, int month, int day) { + Calendar c = new GregorianCalendar(); + + c.set(year, month-1, day, 0, 0, 0); + c.set(Calendar.MILLISECOND, 0); + return HSSFDateUtil.getExcelDate(c.getTime()); + } +} diff --git a/src/testcases/org/apache/poi/hssf/record/formula/atp/TestYearFracCalculatorFromSpreadsheet.java b/src/testcases/org/apache/poi/hssf/record/formula/atp/TestYearFracCalculatorFromSpreadsheet.java new file mode 100644 index 000000000..2cad8e362 --- /dev/null +++ b/src/testcases/org/apache/poi/hssf/record/formula/atp/TestYearFracCalculatorFromSpreadsheet.java @@ -0,0 +1,178 @@ +/* ==================================================================== + 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 java.io.PrintStream; +import java.util.Calendar; +import java.util.GregorianCalendar; +import java.util.Iterator; + +import junit.framework.Assert; +import junit.framework.AssertionFailedError; +import junit.framework.ComparisonFailure; +import junit.framework.TestCase; + +import org.apache.poi.hssf.HSSFTestDataSamples; +import org.apache.poi.hssf.record.formula.eval.EvaluationException; +import org.apache.poi.hssf.usermodel.HSSFCell; +import org.apache.poi.hssf.usermodel.HSSFDateUtil; +import org.apache.poi.hssf.usermodel.HSSFFormulaEvaluator; +import org.apache.poi.hssf.usermodel.HSSFRow; +import org.apache.poi.hssf.usermodel.HSSFSheet; +import org.apache.poi.hssf.usermodel.HSSFWorkbook; + +/** + * Tests YearFracCalculator using test-cases listed in a sample spreadsheet + * + * @author Josh Micich + */ +public final class TestYearFracCalculatorFromSpreadsheet extends TestCase { + + private static final class SS { + + public static final int BASIS_COLUMN = 1; // "B" + public static final int START_YEAR_COLUMN = 2; // "C" + public static final int END_YEAR_COLUMN = 5; // "F" + public static final int YEARFRAC_FORMULA_COLUMN = 11; // "L" + public static final int EXPECTED_RESULT_COLUMN = 13; // "N" + } + + public void testAll() { + + HSSFWorkbook wb = HSSFTestDataSamples.openSampleWorkbook("yearfracExamples.xls"); + HSSFSheet sheet = wb.getSheetAt(0); + HSSFFormulaEvaluator formulaEvaluator = new HSSFFormulaEvaluator(sheet, wb); + int nSuccess = 0; + int nFailures = 0; + int nUnexpectedErrors = 0; + Iterator rowIterator = sheet.rowIterator(); + while(rowIterator.hasNext()) { + HSSFRow row = (HSSFRow) rowIterator.next(); + + HSSFCell cell = row.getCell(SS.YEARFRAC_FORMULA_COLUMN); + if (cell == null || cell.getCellType() != HSSFCell.CELL_TYPE_FORMULA) { + continue; + } + try { + processRow(row, cell, formulaEvaluator); + nSuccess++; + } catch (RuntimeException e) { + nUnexpectedErrors ++; + printShortStackTrace(System.err, e); + } catch (AssertionFailedError e) { + nFailures ++; + printShortStackTrace(System.err, e); + } + } + if (nUnexpectedErrors + nFailures > 0) { + String msg = nFailures + " failures(s) and " + nUnexpectedErrors + + " unexpected errors(s) occurred. See stderr for details"; + throw new AssertionFailedError(msg); + } + if (nSuccess < 1) { + throw new RuntimeException("No test sample cases found"); + } + } + + private static void processRow(HSSFRow row, HSSFCell cell, HSSFFormulaEvaluator formulaEvaluator) { + + double startDate = makeDate(row, SS.START_YEAR_COLUMN); + double endDate = makeDate(row, SS.END_YEAR_COLUMN); + + int basis = getIntCell(row, SS.BASIS_COLUMN); + + double expectedValue = getDoubleCell(row, SS.EXPECTED_RESULT_COLUMN); + + double actualValue; + try { + actualValue = YearFracCalculator.calculate(startDate, endDate, basis); + } catch (EvaluationException e) { + throw new RuntimeException(e); + } + if (expectedValue != actualValue) { + throw new ComparisonFailure("Direct calculate failed - row " + (row.getRowNum()+1), + String.valueOf(expectedValue), String.valueOf(actualValue)); + } + actualValue = formulaEvaluator.evaluate(cell).getNumberValue(); + if (expectedValue != actualValue) { + throw new ComparisonFailure("Formula evaluate failed - row " + (row.getRowNum()+1), + String.valueOf(expectedValue), String.valueOf(actualValue)); + } + } + + private static double makeDate(HSSFRow row, int yearColumn) { + int year = getIntCell(row, yearColumn + 0); + int month = getIntCell(row, yearColumn + 1); + int day = getIntCell(row, yearColumn + 2); + Calendar c = new GregorianCalendar(year, month-1, day, 0, 0, 0); + c.set(Calendar.MILLISECOND, 0); + return HSSFDateUtil.getExcelDate(c.getTime()); + } + + private static int getIntCell(HSSFRow row, int colIx) { + double dVal = getDoubleCell(row, colIx); + if (Math.floor(dVal) != dVal) { + throw new RuntimeException("Non integer value (" + dVal + + ") cell found at column " + (char)('A' + colIx)); + } + return (int)dVal; + } + + private static double getDoubleCell(HSSFRow row, int colIx) { + HSSFCell cell = row.getCell(colIx); + if (cell == null) { + throw new RuntimeException("No cell found at column " + colIx); + } + double dVal = cell.getNumericCellValue(); + return dVal; + } + + /** + * Useful to keep output concise when expecting many failures to be reported by this test case + * TODO - refactor duplicates in other Test~FromSpreadsheet classes + */ + private static void printShortStackTrace(PrintStream ps, Throwable e) { + StackTraceElement[] stes = e.getStackTrace(); + + int startIx = 0; + // skip any top frames inside junit.framework.Assert + while(startIx= endIx) { + // something went wrong. just print the whole stack trace + e.printStackTrace(ps); + } + endIx -= 4; // skip 4 frames of reflection invocation + ps.println(e.toString()); + for(int i=startIx; i 0; x=(short)(x*2) ) { - r = s.createRow((short) x); + r = s.createRow(x); for (short y = 1; y < 256 && y > 0; y= (short) (y +2)) { - c = r.createCell((short) y); + c = r.createCell(y); c.setCellFormula("" + x+"."+y + operator + y +"."+x); } } if (s.getLastRowNum() < Short.MAX_VALUE) { - r = s.createRow((short)0); - c = r.createCell((short)0); + r = s.createRow(0); + c = r.createCell(0); c.setCellFormula("" + Float.MAX_VALUE + operator + Float.MAX_VALUE); } wb.write(out); @@ -216,11 +216,11 @@ public final class TestFormulas extends TestCase { // dont know how to check correct result .. for the moment, we just verify that the file can be read. for (short x = 1; x < Short.MAX_VALUE && x > 0; x=(short)(x*2)) { - r = s.getRow((short) x); + r = s.getRow(x); for (short y = 1; y < 256 && y > 0; y=(short)(y+2)) { - c = r.getCell((short) y); + c = r.getCell(y); assertTrue("got a formula",c.getCellFormula()!=null); assertTrue("loop Formula is as expected "+x+"."+y+operator+y+"."+x+"!="+c.getCellFormula(),( @@ -337,8 +337,8 @@ public final class TestFormulas extends TestCase { HSSFCell c = null; //get our minimum values - r = s.getRow((short)0); - c = r.getCell((short)1); + r = s.getRow(0); + c = r.getCell(1); //get our minimum values assertTrue("minval Formula is as expected A2"+operator+"A3 != "+c.getCellFormula(), ( ("A2"+operator+"A3").equals(c.getCellFormula()) @@ -346,7 +346,7 @@ public final class TestFormulas extends TestCase { for (short x = 1; x < Short.MAX_VALUE && x > 0; x=(short)(x*2)) { - r = s.getRow((short) x); + r = s.getRow(x); for (short y = 1; y < 256 && y > 0; y++) { @@ -372,7 +372,7 @@ public final class TestFormulas extends TestCase { refy2=(short)(y-3); } - c = r.getCell((short) y); + c = r.getCell(y); CellReference cr= new CellReference(refx1, refy1, false, false); ref=cr.formatAsString(); cr=new CellReference(refx2,refy2, false, false); @@ -389,8 +389,8 @@ public final class TestFormulas extends TestCase { } //test our maximum values - r = s.getRow((short)0); - c = r.getCell((short)0); + r = s.getRow(0); + c = r.getCell(0); assertTrue("maxval Formula is as expected",( ("B1"+operator+"IV255").equals(c.getCellFormula()) @@ -416,8 +416,8 @@ public final class TestFormulas extends TestCase { HSSFCell c = null; //get our minimum values - r = s.createRow((short)0); - c = r.createCell((short)1); + r = s.createRow(0); + c = r.createCell(1); c.setCellFormula(formula); wb.write(out); @@ -429,8 +429,8 @@ public final class TestFormulas extends TestCase { s = wb.getSheetAt(0); //get our minimum values - r = s.getRow((short)0); - c = r.getCell((short)1); + r = s.getRow(0); + c = r.getCell(1); assertTrue("minval Formula is as expected", formula.equals(c.getCellFormula()) ); @@ -496,18 +496,18 @@ public final class TestFormulas extends TestCase { HSSFCell c = null; //get our minimum values - r = s.getRow((short)0); - c = r.getCell((short)1); + r = s.getRow(0); + c = r.getCell(1); assertTrue("minval Formula is as expected 1"+operator+"1 != "+c.getCellFormula(), ( ("1"+operator+"1").equals(c.getCellFormula()) )); for (short x = 1; x < Short.MAX_VALUE && x > 0; x=(short)(x*2)) { - r = s.getRow((short) x); + r = s.getRow(x); for (short y = 1; y < 256 && y > 0; y++) { - c = r.getCell((short) y); + c = r.getCell(y); assertTrue("loop Formula is as expected "+x+operator+y+"!="+c.getCellFormula(),( (""+x+operator+y).equals(c.getCellFormula()) @@ -519,8 +519,8 @@ public final class TestFormulas extends TestCase { } //test our maximum values - r = s.getRow((short)0); - c = r.getCell((short)0); + r = s.getRow(0); + c = r.getCell(0); assertTrue("maxval Formula is as expected",( @@ -549,9 +549,9 @@ public final class TestFormulas extends TestCase { HSSFCell c = null; - r = s.createRow((short) 0); + r = s.createRow(0); - c = r.createCell((short) 0); + c = r.createCell(0); c.setCellFormula(function+"(A2:A3)"); @@ -563,7 +563,7 @@ public final class TestFormulas extends TestCase { wb = new HSSFWorkbook(in); s = wb.getSheetAt(0); r = s.getRow(0); - c = r.getCell((short)0); + c = r.getCell(0); assertTrue("function ="+function+"(A2:A3)", ( (function+"(A2:A3)").equals((function+"(A2:A3)")) ) @@ -586,9 +586,9 @@ public final class TestFormulas extends TestCase { HSSFCell c = null; - r = s.createRow((short) 0); + r = s.createRow(0); - c = r.createCell((short) 0); + c = r.createCell(0); c.setCellFormula(function+"(A2,A3)"); @@ -600,7 +600,7 @@ public final class TestFormulas extends TestCase { wb = new HSSFWorkbook(in); s = wb.getSheetAt(0); r = s.getRow(0); - c = r.getCell((short)0); + c = r.getCell(0); assertTrue("function ="+function+"(A2,A3)", ( (function+"(A2,A3)").equals(c.getCellFormula()) ) @@ -624,11 +624,11 @@ public final class TestFormulas extends TestCase { HSSFCell c = null; - r = s.createRow((short) 0); + r = s.createRow(0); - c = r.createCell((short) 0); + c = r.createCell(0); c.setCellFormula(function+"(A2:A4,B2:B4)"); - c=r.createCell((short) 1); + c=r.createCell(1); c.setCellFormula(function+"($A$2:$A4,B$2:B4)"); wb.write(out); @@ -639,13 +639,13 @@ public final class TestFormulas extends TestCase { wb = new HSSFWorkbook(in); s = wb.getSheetAt(0); r = s.getRow(0); - c = r.getCell((short)0); + c = r.getCell(0); assertTrue("function ="+function+"(A2:A4,B2:B4)", ( (function+"(A2:A4,B2:B4)").equals(c.getCellFormula()) ) ); - c=r.getCell((short) 1); + c=r.getCell(1); assertTrue("function ="+function+"($A$2:$A4,B$2:B4)", ( (function+"($A$2:$A4,B$2:B4)").equals(c.getCellFormula()) ) ); @@ -663,17 +663,17 @@ public final class TestFormulas extends TestCase { HSSFCell c = null; - r = s.createRow((short) 0); + r = s.createRow(0); - c = r.createCell((short) 0); + c = r.createCell(0); c.setCellFormula("A3+A2"); - c=r.createCell( (short) 1); + c=r.createCell(1); c.setCellFormula("$A3+$A2"); - c=r.createCell( (short) 2); + c=r.createCell(2); c.setCellFormula("A$3+A$2"); - c=r.createCell( (short) 3); + c=r.createCell(3); c.setCellFormula("$A$3+$A$2"); - c=r.createCell( (short) 4); + c=r.createCell(4); c.setCellFormula("SUM($A$3,$A$2)"); wb.write(out); @@ -684,15 +684,15 @@ public final class TestFormulas extends TestCase { wb = new HSSFWorkbook(in); s = wb.getSheetAt(0); r = s.getRow(0); - c = r.getCell((short)0); + c = r.getCell(0); assertTrue("A3+A2", ("A3+A2").equals(c.getCellFormula())); - c = r.getCell((short)1); + c = r.getCell(1); assertTrue("$A3+$A2", ("$A3+$A2").equals(c.getCellFormula())); - c = r.getCell((short)2); + c = r.getCell(2); assertTrue("A$3+A$2", ("A$3+A$2").equals(c.getCellFormula())); - c = r.getCell((short)3); + c = r.getCell(3); assertTrue("$A$3+$A$2", ("$A$3+$A$2").equals(c.getCellFormula())); - c = r.getCell((short)4); + c = r.getCell(4); assertTrue("SUM($A$3,$A$2)", ("SUM($A$3,$A$2)").equals(c.getCellFormula())); in.close(); } @@ -706,15 +706,15 @@ public final class TestFormulas extends TestCase { HSSFSheet s = wb.createSheet("A"); HSSFRow r = null; HSSFCell c = null; - r = s.createRow((short)0); - c = r.createCell((short)0);c.setCellValue(1); - c = r.createCell((short)1);c.setCellValue(2); + r = s.createRow(0); + c = r.createCell(0);c.setCellValue(1); + c = r.createCell(1);c.setCellValue(2); s = wb.createSheet("B"); - r = s.createRow((short)0); - c=r.createCell((short)0); c.setCellFormula("AVERAGE(A!A1:B1)"); - c=r.createCell((short)1); c.setCellFormula("A!A1+A!B1"); - c=r.createCell((short)2); c.setCellFormula("A!$A$1+A!$B1"); + r = s.createRow(0); + c=r.createCell(0); c.setCellFormula("AVERAGE(A!A1:B1)"); + c=r.createCell(1); c.setCellFormula("A!A1+A!B1"); + c=r.createCell(2); c.setCellFormula("A!$A$1+A!$B1"); wb.write(out); out.close(); @@ -724,9 +724,9 @@ public final class TestFormulas extends TestCase { wb = new HSSFWorkbook(in); s = wb.getSheet("B"); r = s.getRow(0); - c = r.getCell((short)0); + c = r.getCell(0); assertTrue("expected: AVERAGE(A!A1:B1) got: "+c.getCellFormula(), ("AVERAGE(A!A1:B1)").equals(c.getCellFormula())); - c = r.getCell((short)1); + c = r.getCell(1); assertTrue("expected: A!A1+A!B1 got: "+c.getCellFormula(), ("A!A1+A!B1").equals(c.getCellFormula())); in.close(); } @@ -740,29 +740,29 @@ public final class TestFormulas extends TestCase { HSSFCell c = null; - r = s.createRow((short) 0); + r = s.createRow(0); - c = r.createCell((short) 0); + c = r.createCell(0); c.setCellFormula("A3+A2"); - c=r.createCell( (short) 1); + c=r.createCell(1); c.setCellFormula("AVERAGE(A3,A2)"); - c=r.createCell( (short) 2); + c=r.createCell(2); c.setCellFormula("ROW(A3)"); - c=r.createCell( (short) 3); + c=r.createCell(3); c.setCellFormula("AVERAGE(A2:A3)"); - c=r.createCell( (short) 4); + c=r.createCell(4); c.setCellFormula("POWER(A2,A3)"); - c=r.createCell( (short) 5); + c=r.createCell(5); c.setCellFormula("SIN(A2)"); - c=r.createCell( (short) 6); + c=r.createCell(6); c.setCellFormula("SUM(A2:A3)"); - c=r.createCell( (short) 7); + c=r.createCell(7); c.setCellFormula("SUM(A2,A3)"); - r = s.createRow((short) 1);c=r.createCell( (short) 0); c.setCellValue(2.0); - r = s.createRow((short) 2);c=r.createCell( (short) 0); c.setCellValue(3.0); + r = s.createRow(1);c=r.createCell(0); c.setCellValue(2.0); + r = s.createRow(2);c=r.createCell(0); c.setCellValue(3.0); wb.write(out); out.close(); @@ -778,10 +778,10 @@ public final class TestFormulas extends TestCase { HSSFSheet s = wb.createSheet("A"); HSSFRow r = null; HSSFCell c = null; - r = s.createRow((short)0); - c=r.createCell((short)1); c.setCellFormula("UPPER(\"abc\")"); - c=r.createCell((short)2); c.setCellFormula("LOWER(\"ABC\")"); - c=r.createCell((short)3); c.setCellFormula("CONCATENATE(\" my \",\" name \")"); + r = s.createRow(0); + c=r.createCell(1); c.setCellFormula("UPPER(\"abc\")"); + c=r.createCell(2); c.setCellFormula("LOWER(\"ABC\")"); + c=r.createCell(3); c.setCellFormula("CONCATENATE(\" my \",\" name \")"); wb.write(out); out.close(); @@ -789,7 +789,7 @@ public final class TestFormulas extends TestCase { wb = openSample("StringFormulas.xls"); s = wb.getSheetAt(0); r = s.getRow(0); - c = r.getCell((short)0); + c = r.getCell(0); assertTrue("expected: UPPER(\"xyz\") got "+c.getCellFormula(), ("UPPER(\"xyz\")").equals(c.getCellFormula())); //c = r.getCell((short)1); //assertTrue("expected: A!A1+A!B1 got: "+c.getCellFormula(), ("A!A1+A!B1").equals(c.getCellFormula())); @@ -807,8 +807,8 @@ public final class TestFormulas extends TestCase { HSSFSheet s = wb.createSheet("A"); HSSFRow r = null; HSSFCell c = null; - r = s.createRow((short)0); - c=r.createCell((short)1); c.setCellFormula("IF(A1 0) { + throw new AssertionFailedError("Indentified bug 45682"); + } + throw e; + } + assertEquals(2, wb.getNumberOfSheets()); + } } diff --git a/src/testcases/org/apache/poi/hssf/usermodel/TestHSSFDateUtil.java b/src/testcases/org/apache/poi/hssf/usermodel/TestHSSFDateUtil.java index 377a8ffe2..9e451ee05 100644 --- a/src/testcases/org/apache/poi/hssf/usermodel/TestHSSFDateUtil.java +++ b/src/testcases/org/apache/poi/hssf/usermodel/TestHSSFDateUtil.java @@ -16,7 +16,6 @@ limitations under the License. ==================================================================== */ - package org.apache.poi.hssf.usermodel; import java.util.Calendar; @@ -52,9 +51,7 @@ public final class TestHSSFDateUtil extends TestCase { * Checks the date conversion functions in the HSSFDateUtil class. */ - public void testDateConversion() - throws Exception - { + public void testDateConversion() { // Iteratating over the hours exposes any rounding issues. for (int hour = 0; hour < 23; hour++) @@ -131,7 +128,7 @@ public final class TestHSSFDateUtil extends TestCase { for (int hour = 0; hour < 24; hour++, excelDate += oneHour) { // Skip 02:00 CET as that is the Daylight change time - // and Java converts it automatically to 03:00 CEST + // and Java converts it automatically to 03:00 CEST if (hour == 2) { continue; } @@ -186,7 +183,7 @@ public final class TestHSSFDateUtil extends TestCase { HSSFDateUtil.getExcelDate(javaDate, false), oneMinute); } } - + /** * Tests that we deal with time-zones properly */ @@ -207,8 +204,7 @@ public final class TestHSSFDateUtil extends TestCase { assertEquals("Checking timezone " + id, expected.getTime(), javaDate.getTime()); } } - - + /** * Tests that we correctly detect date formats as such */ @@ -220,7 +216,7 @@ public final class TestHSSFDateUtil extends TestCase { assertTrue( HSSFDateUtil.isInternalDateFormat(builtins[i]) ); assertTrue( HSSFDateUtil.isADateFormat(builtins[i],formatStr) ); } - + // Now try a few built-in non date formats builtins = new short[] { 0x01, 0x02, 0x17, 0x1f, 0x30 }; for(int i=0; i blank // 5 -> num - row.createCell((short)0).setCellValue(new HSSFRichTextString("test")); - row.createCell((short)1).setCellValue(3.2); - row.createCell((short)4, HSSFCell.CELL_TYPE_BLANK); - row.createCell((short)5).setCellValue(4); + row.createCell(0).setCellValue(new HSSFRichTextString("test")); + row.createCell(1).setCellValue(3.2); + row.createCell(4, HSSFCell.CELL_TYPE_BLANK); + row.createCell(5).setCellValue(4); // First up, no policy given, uses default assertEquals(HSSFCell.CELL_TYPE_STRING, row.getCell(0).getCellType()); @@ -281,12 +281,12 @@ public final class TestHSSFRow extends TestCase { public void testRowHeight() { HSSFWorkbook workbook = new HSSFWorkbook(); HSSFSheet sheet = workbook.createSheet(); - HSSFRow row1 = sheet.createRow( (short) 0); + HSSFRow row1 = sheet.createRow(0); assertEquals(0xFF, row1.getHeight()); assertEquals(sheet.getDefaultRowHeight(), row1.getHeight()); - HSSFRow row2 = sheet.createRow( (short) 1); + HSSFRow row2 = sheet.createRow(1); row2.setHeight((short)400); assertEquals(400, row2.getHeight()); diff --git a/src/testcases/org/apache/poi/hssf/usermodel/TestHSSFSheet.java b/src/testcases/org/apache/poi/hssf/usermodel/TestHSSFSheet.java index a24e5e797..4c8c8c5d6 100644 --- a/src/testcases/org/apache/poi/hssf/usermodel/TestHSSFSheet.java +++ b/src/testcases/org/apache/poi/hssf/usermodel/TestHSSFSheet.java @@ -147,10 +147,10 @@ public final class TestHSSFSheet extends TestCase { public void testReadBooleans() { HSSFWorkbook workbook = new HSSFWorkbook(); HSSFSheet sheet = workbook.createSheet("Test boolean"); - HSSFRow row = sheet.createRow((short) 2); - HSSFCell cell = row.createCell((short) 9); + HSSFRow row = sheet.createRow(2); + HSSFCell cell = row.createCell(9); cell.setCellValue(true); - cell = row.createCell((short) 11); + cell = row.createCell(11); cell.setCellValue(true); workbook = HSSFTestDataSamples.writeOutAndReadBack(workbook); @@ -164,7 +164,7 @@ public final class TestHSSFSheet extends TestCase { public void testRemoveRow() { HSSFWorkbook workbook = new HSSFWorkbook(); HSSFSheet sheet = workbook.createSheet("Test boolean"); - HSSFRow row = sheet.createRow((short) 2); + HSSFRow row = sheet.createRow(2); sheet.removeRow(row); } @@ -186,8 +186,8 @@ public final class TestHSSFSheet extends TestCase { HSSFWorkbook workbook = new HSSFWorkbook(); HSSFSheet sheet = workbook.createSheet("Test Clone"); HSSFRow row = sheet.createRow(0); - HSSFCell cell = row.createCell((short) 0); - HSSFCell cell2 = row.createCell((short) 1); + HSSFCell cell = row.createCell(0); + HSSFCell cell2 = row.createCell(1); cell.setCellValue(new HSSFRichTextString("clone_test")); cell2.setCellFormula("sin(1)"); @@ -216,8 +216,8 @@ public final class TestHSSFSheet extends TestCase { public void testCloneSheetMultipleTimes() { HSSFWorkbook workbook = new HSSFWorkbook(); HSSFSheet sheet = workbook.createSheet("Test Clone"); - HSSFRow row = sheet.createRow((short) 0); - HSSFCell cell = row.createCell((short) 0); + HSSFRow row = sheet.createRow(0); + HSSFCell cell = row.createCell(0); cell.setCellValue(new HSSFRichTextString("clone_test")); //Clone the sheet multiple times workbook.cloneSheet(0); @@ -510,11 +510,11 @@ public final class TestHSSFSheet extends TestCase { HSSFWorkbook wb = new HSSFWorkbook(); HSSFSheet sheet = wb.createSheet(); HSSFRow row = sheet.createRow(0); - HSSFCell cell = row.createCell((short)0); + HSSFCell cell = row.createCell(0); cell.setCellValue(new HSSFRichTextString("first row, first cell")); row = sheet.createRow(1); - cell = row.createCell((short)1); + cell = row.createCell(1); cell.setCellValue(new HSSFRichTextString("second row, second cell")); CellRangeAddress region = new CellRangeAddress(1, 1, 0, 1); @@ -617,13 +617,13 @@ public final class TestHSSFSheet extends TestCase { HSSFWorkbook wb = new HSSFWorkbook(); HSSFSheet s = wb.createSheet("Sheet1"); HSSFRow r = s.createRow(0); - r.createCell((short) 0).setCellValue(1); - r.createCell((short) 1).setCellFormula("A1*2"); + r.createCell(0).setCellValue(1); + r.createCell(1).setCellFormula("A1*2"); HSSFSheet s1 = wb.cloneSheet(0); r = s1.getRow(0); - assertEquals("double", r.getCell((short) 0).getNumericCellValue(), 1, 0); // sanity check - assertNotNull(r.getCell((short) 1)); - assertEquals("formula", r.getCell((short) 1).getCellFormula(), "A1*2"); + assertEquals("double", r.getCell(0).getNumericCellValue(), 1, 0); // sanity check + assertNotNull(r.getCell(1)); + assertEquals("formula", r.getCell(1).getCellFormula(), "A1*2"); } /** test that new default column styles get applied */ @@ -633,7 +633,7 @@ public final class TestHSSFSheet extends TestCase { HSSFSheet s = wb.createSheet(); s.setDefaultColumnStyle((short) 0, style); HSSFRow r = s.createRow(0); - HSSFCell c = r.createCell((short) 0); + HSSFCell c = r.createCell(0); assertEquals("style should match", style.getIndex(), c.getCellStyle().getIndex()); } @@ -710,8 +710,8 @@ public final class TestHSSFSheet extends TestCase { HSSFSheet sheet = workbook.getSheetAt(0); HSSFSheet sheet2 = workbook.getSheetAt(0); HSSFRow row = sheet.getRow(0); - row.createCell((short) 0).setCellValue(5); - row.createCell((short) 1).setCellValue(8); + row.createCell(0).setCellValue(5); + row.createCell(1).setCellValue(8); assertFalse(sheet.getForceFormulaRecalculation()); assertFalse(sheet2.getForceFormulaRecalculation()); diff --git a/src/testcases/org/apache/poi/hssf/usermodel/TestHSSFWorkbook.java b/src/testcases/org/apache/poi/hssf/usermodel/TestHSSFWorkbook.java index 35a2d955f..658a3f488 100644 --- a/src/testcases/org/apache/poi/hssf/usermodel/TestHSSFWorkbook.java +++ b/src/testcases/org/apache/poi/hssf/usermodel/TestHSSFWorkbook.java @@ -290,10 +290,10 @@ public final class TestHSSFWorkbook extends TestCase { assertEquals(true, sheet3.isActive()); if (false) { // helpful if viewing this workbook in excel: - sheet1.createRow(0).createCell((short)0).setCellValue(new HSSFRichTextString("Sheet1")); - sheet2.createRow(0).createCell((short)0).setCellValue(new HSSFRichTextString("Sheet2")); - sheet3.createRow(0).createCell((short)0).setCellValue(new HSSFRichTextString("Sheet3")); - sheet4.createRow(0).createCell((short)0).setCellValue(new HSSFRichTextString("Sheet4")); + sheet1.createRow(0).createCell(0).setCellValue(new HSSFRichTextString("Sheet1")); + sheet2.createRow(0).createCell(0).setCellValue(new HSSFRichTextString("Sheet2")); + sheet3.createRow(0).createCell(0).setCellValue(new HSSFRichTextString("Sheet3")); + sheet4.createRow(0).createCell(0).setCellValue(new HSSFRichTextString("Sheet4")); try { File fOut = TempFile.createTempFile("sheetMultiSelect", ".xls"); diff --git a/src/testcases/org/apache/poi/hssf/usermodel/TestReadWriteChart.java b/src/testcases/org/apache/poi/hssf/usermodel/TestReadWriteChart.java index 342f6e26f..186ee18a6 100644 --- a/src/testcases/org/apache/poi/hssf/usermodel/TestReadWriteChart.java +++ b/src/testcases/org/apache/poi/hssf/usermodel/TestReadWriteChart.java @@ -39,14 +39,14 @@ public final class TestReadWriteChart extends TestCase { HSSFWorkbook workbook = HSSFTestDataSamples.openSampleWorkbook("SimpleChart.xls"); HSSFSheet sheet = workbook.getSheetAt(0); HSSFRow firstRow = sheet.getRow(0); - HSSFCell firstCell = firstRow.getCell(( short ) 0); + HSSFCell firstCell = firstRow.getCell(0); //System.out.println("first assertion for date"); assertEquals(new GregorianCalendar(2000, 0, 1, 10, 51, 2).getTime(), HSSFDateUtil .getJavaDate(firstCell.getNumericCellValue(), false)); - HSSFRow row = sheet.createRow(( short ) 15); - HSSFCell cell = row.createCell(( short ) 1); + HSSFRow row = sheet.createRow(15); + HSSFCell cell = row.createCell(1); cell.setCellValue(22); Sheet newSheet = workbook.getSheetAt(0).getSheet(); diff --git a/src/testcases/org/apache/poi/hssf/usermodel/TestSheetHiding.java b/src/testcases/org/apache/poi/hssf/usermodel/TestSheetHiding.java index 62a26e90b..ddd910159 100644 --- a/src/testcases/org/apache/poi/hssf/usermodel/TestSheetHiding.java +++ b/src/testcases/org/apache/poi/hssf/usermodel/TestSheetHiding.java @@ -61,10 +61,10 @@ public final class TestSheetHiding extends TestCase { assertEquals(1, wbU.getSheetAt(1).getRow(0).getLastCellNum()); // Text should be sheet based - assertEquals("Sheet1A1", wbH.getSheetAt(0).getRow(0).getCell((short)0).getRichStringCellValue().getString()); - assertEquals("Sheet2A1", wbH.getSheetAt(1).getRow(0).getCell((short)0).getRichStringCellValue().getString()); - assertEquals("Sheet1A1", wbU.getSheetAt(0).getRow(0).getCell((short)0).getRichStringCellValue().getString()); - assertEquals("Sheet2A1", wbU.getSheetAt(1).getRow(0).getCell((short)0).getRichStringCellValue().getString()); + assertEquals("Sheet1A1", wbH.getSheetAt(0).getRow(0).getCell(0).getRichStringCellValue().getString()); + assertEquals("Sheet2A1", wbH.getSheetAt(1).getRow(0).getCell(0).getRichStringCellValue().getString()); + assertEquals("Sheet1A1", wbU.getSheetAt(0).getRow(0).getCell(0).getRichStringCellValue().getString()); + assertEquals("Sheet2A1", wbU.getSheetAt(1).getRow(0).getCell(0).getRichStringCellValue().getString()); } /** diff --git a/src/testcases/org/apache/poi/hssf/usermodel/TestSheetShiftRows.java b/src/testcases/org/apache/poi/hssf/usermodel/TestSheetShiftRows.java index 03d67cc21..101bd325d 100755 --- a/src/testcases/org/apache/poi/hssf/usermodel/TestSheetShiftRows.java +++ b/src/testcases/org/apache/poi/hssf/usermodel/TestSheetShiftRows.java @@ -99,8 +99,8 @@ public final class TestSheetShiftRows extends TestCase { public void testShiftRow(){ HSSFWorkbook b = new HSSFWorkbook(); HSSFSheet s = b.createSheet(); - s.createRow(0).createCell((short)0).setCellValue("TEST1"); - s.createRow(3).createCell((short)0).setCellValue("TEST2"); + s.createRow(0).createCell(0).setCellValue("TEST1"); + s.createRow(3).createCell(0).setCellValue("TEST2"); s.shiftRows(0,4,1); } @@ -112,8 +112,8 @@ public final class TestSheetShiftRows extends TestCase { public void testShiftRow0(){ HSSFWorkbook b = new HSSFWorkbook(); HSSFSheet s = b.createSheet(); - s.createRow(0).createCell((short)0).setCellValue("TEST1"); - s.createRow(3).createCell((short)0).setCellValue("TEST2"); + s.createRow(0).createCell(0).setCellValue("TEST1"); + s.createRow(3).createCell(0).setCellValue("TEST2"); s.shiftRows(0,4,1); } @@ -125,7 +125,7 @@ public final class TestSheetShiftRows extends TestCase { HSSFWorkbook b = new HSSFWorkbook(); HSSFSheet s = b.createSheet(); HSSFRow row = s.createRow(4); - row.createCell((short)0).setCellValue("test"); + row.createCell(0).setCellValue("test"); s.setRowBreak(4); s.shiftRows(4, 4, 2); @@ -203,34 +203,34 @@ public final class TestSheetShiftRows extends TestCase { HSSFSheet sheet = wb.getSheet("Sheet1"); assertEquals(19, sheet.getLastRowNum()); - assertEquals("cell B1 (ref)", sheet.getRow(0).getCell((short)3).getRichStringCellValue().toString()); - assertEquals("CONCATENATE(B1,\" (ref)\")", sheet.getRow(0).getCell((short)3).getCellFormula()); - assertEquals("cell B2 (ref)", sheet.getRow(1).getCell((short)3).getRichStringCellValue().toString()); - assertEquals("CONCATENATE(B2,\" (ref)\")", sheet.getRow(1).getCell((short)3).getCellFormula()); - assertEquals("cell B3 (ref)", sheet.getRow(2).getCell((short)3).getRichStringCellValue().toString()); - assertEquals("CONCATENATE(B3,\" (ref)\")", sheet.getRow(2).getCell((short)3).getCellFormula()); - assertEquals("cell B2 (ref)", sheet.getRow(6).getCell((short)1).getRichStringCellValue().toString()); - assertEquals("CONCATENATE(B2,\" (ref)\")", sheet.getRow(6).getCell((short)1).getCellFormula()); + assertEquals("cell B1 (ref)", sheet.getRow(0).getCell(3).getRichStringCellValue().toString()); + assertEquals("CONCATENATE(B1,\" (ref)\")", sheet.getRow(0).getCell(3).getCellFormula()); + assertEquals("cell B2 (ref)", sheet.getRow(1).getCell(3).getRichStringCellValue().toString()); + assertEquals("CONCATENATE(B2,\" (ref)\")", sheet.getRow(1).getCell(3).getCellFormula()); + assertEquals("cell B3 (ref)", sheet.getRow(2).getCell(3).getRichStringCellValue().toString()); + assertEquals("CONCATENATE(B3,\" (ref)\")", sheet.getRow(2).getCell(3).getCellFormula()); + assertEquals("cell B2 (ref)", sheet.getRow(6).getCell(1).getRichStringCellValue().toString()); + assertEquals("CONCATENATE(B2,\" (ref)\")", sheet.getRow(6).getCell(1).getCellFormula()); sheet.shiftRows(1, 1, 10); // Row 1 => Row 11 // So strings on row 11 unchanged, but reference in formula is - assertEquals("cell B1 (ref)", sheet.getRow(0).getCell((short)3).getRichStringCellValue().toString()); - assertEquals("CONCATENATE(B1,\" (ref)\")", sheet.getRow(0).getCell((short)3).getCellFormula()); + assertEquals("cell B1 (ref)", sheet.getRow(0).getCell(3).getRichStringCellValue().toString()); + assertEquals("CONCATENATE(B1,\" (ref)\")", sheet.getRow(0).getCell(3).getCellFormula()); assertEquals(0, sheet.getRow(1).getPhysicalNumberOfCells()); // still save b2 - assertEquals("cell B2 (ref)", sheet.getRow(11).getCell((short)3).getRichStringCellValue().toString()); + assertEquals("cell B2 (ref)", sheet.getRow(11).getCell(3).getRichStringCellValue().toString()); // but points to b12 - assertEquals("CONCATENATE(B12,\" (ref)\")", sheet.getRow(11).getCell((short)3).getCellFormula()); + assertEquals("CONCATENATE(B12,\" (ref)\")", sheet.getRow(11).getCell(3).getCellFormula()); - assertEquals("cell B3 (ref)", sheet.getRow(2).getCell((short)3).getRichStringCellValue().toString()); - assertEquals("CONCATENATE(B3,\" (ref)\")", sheet.getRow(2).getCell((short)3).getCellFormula()); + assertEquals("cell B3 (ref)", sheet.getRow(2).getCell(3).getRichStringCellValue().toString()); + assertEquals("CONCATENATE(B3,\" (ref)\")", sheet.getRow(2).getCell(3).getCellFormula()); // one on a non-shifted row also updated - assertEquals("cell B2 (ref)", sheet.getRow(6).getCell((short)1).getRichStringCellValue().toString()); - assertEquals("CONCATENATE(B12,\" (ref)\")", sheet.getRow(6).getCell((short)1).getCellFormula()); + assertEquals("cell B2 (ref)", sheet.getRow(6).getCell(1).getRichStringCellValue().toString()); + assertEquals("CONCATENATE(B12,\" (ref)\")", sheet.getRow(6).getCell(1).getCellFormula()); } } diff --git a/src/testcases/org/apache/poi/hssf/usermodel/TestUnicodeWorkbook.java b/src/testcases/org/apache/poi/hssf/usermodel/TestUnicodeWorkbook.java index d67c3f469..2a9215285 100644 --- a/src/testcases/org/apache/poi/hssf/usermodel/TestUnicodeWorkbook.java +++ b/src/testcases/org/apache/poi/hssf/usermodel/TestUnicodeWorkbook.java @@ -57,14 +57,14 @@ public class TestUnicodeWorkbook extends TestCase { f.setRight("\u20ac"); HSSFRow r = s.createRow(0); - HSSFCell c = r.createCell((short)1); + HSSFCell c = r.createCell(1); c.setCellValue(12.34); c.getCellStyle().setDataFormat(fmt); - HSSFCell c2 = r.createCell((short)2); + HSSFCell c2 = r.createCell(2); c.setCellValue(new HSSFRichTextString("\u20ac")); - HSSFCell c3 = r.createCell((short)3); + HSSFCell c3 = r.createCell(3); String formulaString = "TEXT(12.34,\"\u20ac###,##\")"; c3.setCellFormula(formulaString); @@ -95,16 +95,16 @@ public class TestUnicodeWorkbook extends TestCase { //Test the dataformat r = s.getRow(0); - c = r.getCell((short)1); + c = r.getCell(1); df = wb.createDataFormat(); assertEquals(formatStr, df.getFormat(c.getCellStyle().getDataFormat())); //Test the cell string value - c2 = r.getCell((short)2); + c2 = r.getCell(2); assertEquals(c.getRichStringCellValue().getString(), "\u20ac"); //Test the cell formula - c3 = r.getCell((short)3); + c3 = r.getCell(3); assertEquals(c3.getCellFormula(), formulaString); } @@ -122,7 +122,7 @@ public class TestUnicodeWorkbook extends TestCase { HSSFSheet s = wb.createSheet("test"); HSSFRow r = s.createRow(0); - HSSFCell c = r.createCell((short)1); + HSSFCell c = r.createCell(1); c.setCellValue(new HSSFRichTextString("\u00e4")); //Confirm that the sring will be compressed @@ -140,7 +140,7 @@ public class TestUnicodeWorkbook extends TestCase { s = wb.getSheet("test"); assertNotNull(s); - c = r.getCell((short)1); + c = r.getCell(1); assertEquals(c.getRichStringCellValue().getString(), "\u00e4"); } diff --git a/src/testcases/org/apache/poi/hssf/usermodel/TestWorkbook.java b/src/testcases/org/apache/poi/hssf/usermodel/TestWorkbook.java index c0231cdfe..c6fa2ee0d 100644 --- a/src/testcases/org/apache/poi/hssf/usermodel/TestWorkbook.java +++ b/src/testcases/org/apache/poi/hssf/usermodel/TestWorkbook.java @@ -96,7 +96,7 @@ public final class TestWorkbook extends TestCase { c.setCellValue(rownum * 10000 + cellnum + ((( double ) rownum / 1000) + (( double ) cellnum / 10000))); - c = r.createCell(( short ) (cellnum + 1)); + c = r.createCell(cellnum + 1); c.setCellValue(new HSSFRichTextString("TEST")); } } @@ -142,7 +142,7 @@ public final class TestWorkbook extends TestCase { c.setCellValue(rownum * 10000 + cellnum + ((( double ) rownum / 1000) + (( double ) cellnum / 10000))); - c = r.createCell(( short ) (cellnum + 1)); + c = r.createCell(cellnum + 1); c.setCellValue(new HSSFRichTextString("TEST")); } } @@ -226,8 +226,8 @@ public final class TestWorkbook extends TestCase { short df = format.getFormat("0.0"); cs.setDataFormat(df); - r = s.createRow((short)0); - c = r.createCell((short)0); + r = s.createRow(0); + c = r.createCell(0); c.setCellStyle(cs); c.setCellValue(1.25); @@ -239,7 +239,7 @@ public final class TestWorkbook extends TestCase { HSSFWorkbook workbook = new HSSFWorkbook(fs); HSSFSheet sheet = workbook.getSheetAt(0); HSSFCell cell = - sheet.getRow(( short ) 0).getCell(( short ) 0); + sheet.getRow(0).getCell(0); format = workbook.createDataFormat(); assertEquals(1.25,cell.getNumericCellValue(), 1e-10); @@ -350,7 +350,7 @@ public final class TestWorkbook extends TestCase { for (int k = 0; k < 4; k++) { - HSSFCell cell = sheet.getRow(( short ) k).getCell(( short ) 0); + HSSFCell cell = sheet.getRow(k).getCell(0); cell.setCellValue(new HSSFRichTextString(REPLACED)); } @@ -360,7 +360,7 @@ public final class TestWorkbook extends TestCase { sheet = workbook.getSheetAt(0); for (int k = 0; k < 4; k++) { - HSSFCell cell = sheet.getRow(( short ) k).getCell(( short ) 0); + HSSFCell cell = sheet.getRow(k).getCell(0); assertEquals(REPLACED, cell.getRichStringCellValue().getString()); } @@ -439,7 +439,7 @@ public final class TestWorkbook extends TestCase { c.setCellValue(rownum * 10000 + cellnum + ((( double ) rownum / 1000) + (( double ) cellnum / 10000))); - c = r.createCell(( short ) (cellnum + 1)); + c = r.createCell(cellnum + 1); c.setCellValue(new HSSFRichTextString("TEST")); } } @@ -530,7 +530,7 @@ public final class TestWorkbook extends TestCase { for ( i = 0, j = 32771; j > 0; i++, j-- ) { row = sheet.createRow(i); - cell = row.createCell((short) 0); + cell = row.createCell(0); cell.setCellValue(i); } sanityChecker.checkHSSFWorkbook(workbook); @@ -556,7 +556,7 @@ public final class TestWorkbook extends TestCase { HSSFRow row = sheet.createRow(0); - HSSFCell cell = row.createCell((short)1); + HSSFCell cell = row.createCell(1); cell.setCellValue(new HSSFRichTextString("hi"));