]> source.dussan.org Git - poi.git/commitdiff
Few little short/int tweaks, and then tests to show that FormulaEvaluator plays nicel...
authorNick Burch <nick@apache.org>
Sat, 29 Mar 2008 22:45:11 +0000 (22:45 +0000)
committerNick Burch <nick@apache.org>
Sat, 29 Mar 2008 22:45:11 +0000 (22:45 +0000)
git-svn-id: https://svn.apache.org/repos/asf/poi/branches/ooxml@642634 13f79535-47bb-0310-9956-ffa450edef68

src/java/org/apache/poi/hssf/record/formula/functions/Count.java
src/java/org/apache/poi/hssf/usermodel/HSSFRow.java
src/ooxml/interfaces-jdk15/org/apache/poi/ss/usermodel/Row.java
src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFCell.java
src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFRow.java
src/ooxml/testcases/org/apache/poi/xssf/usermodel/TestXSSFFormulaEvaluation.java [new file with mode: 0644]

index 736c37c1b7896f20fc0481cffd0fff9eaa1bbcd0..eb55fc4a421b4cd8c2773b7202d6475ce0f3297c 100644 (file)
  */
 package org.apache.poi.hssf.record.formula.functions;
 
-public class Count extends NotImplementedFunction {
+import org.apache.poi.hssf.record.formula.eval.AreaEval;
+import org.apache.poi.hssf.record.formula.eval.BlankEval;
+import org.apache.poi.hssf.record.formula.eval.ErrorEval;
+import org.apache.poi.hssf.record.formula.eval.Eval;
+import org.apache.poi.hssf.record.formula.eval.NumberEval;
+import org.apache.poi.hssf.record.formula.eval.RefEval;
+import org.apache.poi.hssf.record.formula.eval.ValueEval;
 
-}
+/**
+ * Counts the number of cells that contain numeric data within
+ *  the list of arguments. 
+ *
+ * Excel Syntax
+ * COUNT(value1,value2,...)
+ * Value1, value2, ...   are 1 to 30 arguments representing the values or ranges to be counted.
+ * 
+ * TODO: Check this properly matches excel on edge cases
+ *  like formula cells, error cells etc
+ */
+public class Count implements Function {
+
+       public Eval evaluate(Eval[] args, int srcCellRow, short srcCellCol) {
+               int nArgs = args.length;
+               if (nArgs < 1) {
+                       // too few arguments
+                       return ErrorEval.VALUE_INVALID;
+               }
+
+               if (nArgs > 30) {
+                       // too many arguments
+                       return ErrorEval.VALUE_INVALID;
+               }
+               
+               int temp = 0;
+               
+               for(int i=0; i<nArgs; i++) {
+                       temp += countArg(args[i]);
+                       
+               }
+               return new NumberEval(temp);
+       }
+
+       private static int countArg(Eval eval) {
+        if (eval instanceof AreaEval) {
+            AreaEval ae = (AreaEval) eval;
+            return countAreaEval(ae);
+        }
+        if (eval instanceof RefEval) {
+            RefEval refEval = (RefEval)eval;
+                       return countValue(refEval.getInnerValueEval());
+        }
+        if (eval instanceof NumberEval) {
+            return 1;
+        }
+               
+               throw new RuntimeException("Unexpected eval type (" + eval.getClass().getName() + ")");
+       }
+
+       private static int countAreaEval(AreaEval ae) {
+               
+               int temp = 0;
+               ValueEval[] values = ae.getValues();
+               for (int i = 0; i < values.length; i++) {
+                       ValueEval val = values[i];
+                       if(val == null) {
+                               // seems to occur.  Really we would have expected BlankEval
+                               continue;
+                       }
+                       temp += countValue(val);
+                       
+               }
+               return temp;
+       }
+
+       private static int countValue(ValueEval valueEval) {
+               
+               if(valueEval == BlankEval.INSTANCE) {
+                       return 0;
+               }
+               
+               if(valueEval instanceof BlankEval) {
+                       // wouldn't need this if BlankEval was final
+                       return 0;
+               }
+
+               if(valueEval instanceof ErrorEval) {
+                       // note - error values not counted
+                       return 0;
+               }
+               
+               if(valueEval instanceof NumberEval)
+                       return 1;
+
+               return 0;
+       }
+}
\ No newline at end of file
index fa183b43cec07d9d0d0ddafffe4a81781083fb81..06a704d7f00e184ac467f9c34d208f8f7aa38647 100644 (file)
@@ -120,23 +120,40 @@ public final class HSSFRow implements Comparable, Row {
      *
      * @return HSSFCell a high level representation of the created cell.
      */
-
     public HSSFCell createCell(short column)
     {
-      return this.createCell(column,HSSFCell.CELL_TYPE_BLANK);
+        return this.createCell(column,HSSFCell.CELL_TYPE_BLANK);
     }
 
     /**
      * Use this to create new cells within the row and return it.
      * <p>
      * The cell that is returned is a CELL_TYPE_BLANK. The type can be changed
-     * either through calling setCellValue or setCellType.
+     * either through calling <code>setCellValue</code> or <code>setCellType</code>.
      *
      * @param column - the column number this cell represents
      *
      * @return HSSFCell a high level representation of the created cell.
      */
+    public HSSFCell createCell(int column)
+    {
+       short shortCellNum = (short)column;
+       if(column > 0x7FFF) {
+               shortCellNum = (short)(0xffff - column);
+       }
+        return this.createCell(shortCellNum,HSSFCell.CELL_TYPE_BLANK);
+    }
 
+    /**
+     * Use this to create new cells within the row and return it.
+     * <p>
+     * The cell that is returned is a CELL_TYPE_BLANK. The type can be changed
+     * either through calling setCellValue or setCellType.
+     *
+     * @param column - the column number this cell represents
+     *
+     * @return HSSFCell a high level representation of the created cell.
+     */
     public HSSFCell createCell(short column, int type)
     {
         HSSFCell cell = new HSSFCell(book, sheet, getRowNum(), column, type);
index 012ee81d04db0a788e0b828a13116ed8497cc903..b010233d1035b6c7db44c97e8804211e8087d31a 100644 (file)
@@ -33,9 +33,20 @@ public interface Row extends Iterable {
      *
      * @param column - the column number this cell represents
      *
-     * @return HSSFCell a high level representation of the created cell.
+     * @return Cell a high level representation of the created cell.
      */
+    Cell createCell(int column);
 
+    /**
+     * Use this to create new cells within the row and return it.
+     * <p>
+     * The cell that is returned is a CELL_TYPE_BLANK. The type can be changed
+     * either through calling <code>setCellValue</code> or <code>setCellType</code>.
+     *
+     * @param column - the column number this cell represents
+     *
+     * @return Cell a high level representation of the created cell.
+     */
     Cell createCell(short column);
 
     /**
index 3d15cd919e25a071cd1931ffde8305011a7d95d8..e566181c8f972f3a832fc9289f06f6ade07fe1bb 100644 (file)
@@ -39,7 +39,7 @@ public class XSSFCell implements Cell {
     private static final String TRUE_AS_STRING  = "1";
     private final CTCell cell;
     private final XSSFRow row;
-    private short cellNum;
+    private int cellNum;
     private SharedStringSource sharedStringSource;
     private StylesSource stylesSource;
     
@@ -91,7 +91,7 @@ public class XSSFCell implements Cell {
     }
 
     public short getCellNum() {
-        return this.cellNum;
+        return (short)this.cellNum;
     }
 
     public CellStyle getCellStyle() {
@@ -212,6 +212,9 @@ public class XSSFCell implements Cell {
             
     }
 
+    public void setCellNum(int num) {
+       setCellNum((short)num);
+    }
     public void setCellNum(short num) {
         checkBounds(num);
         this.cellNum = num;
index dba418864984cb6d67285ce733f2b7bda6ec6ffe..1a1e831a2ac12f8bd6a513718f9a2adf6676d19d 100644 (file)
@@ -79,9 +79,12 @@ public class XSSFRow implements Row {
         return 0;
     }
 
-    public Cell createCell(short column) {
+    public Cell createCell(int column) {
        return createCell(column, Cell.CELL_TYPE_BLANK);
     }
+    public Cell createCell(short column) {
+       return createCell((int)column);
+    }
 
     /**
      * Add a new empty cell to this row.
@@ -91,7 +94,7 @@ public class XSSFRow implements Row {
      * @param type TODO
      * @return The new cell.
      */
-    protected XSSFCell addCell(short column, int index, int type) {
+    protected XSSFCell addCell(int column, int index, int type) {
         CTCell ctcell = row.insertNewC(index);
         XSSFCell xcell = new XSSFCell(this, ctcell);
         xcell.setCellNum(column);
@@ -102,6 +105,9 @@ public class XSSFRow implements Row {
     }
 
     public Cell createCell(short column, int type) {
+       return createCell((int)column, type);
+    }
+    public Cell createCell(int column, int type) {
         int index = 0;
         for (Cell c : this.cells) {
             if (c.getCellNum() == column) {
diff --git a/src/ooxml/testcases/org/apache/poi/xssf/usermodel/TestXSSFFormulaEvaluation.java b/src/ooxml/testcases/org/apache/poi/xssf/usermodel/TestXSSFFormulaEvaluation.java
new file mode 100644 (file)
index 0000000..4f2bf1c
--- /dev/null
@@ -0,0 +1,104 @@
+/* ====================================================================
+   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.xssf.usermodel;
+
+import org.apache.poi.ss.usermodel.Cell;
+import org.apache.poi.ss.usermodel.FormulaEvaluator;
+import org.apache.poi.ss.usermodel.Row;
+import org.apache.poi.ss.usermodel.Sheet;
+import org.apache.poi.ss.usermodel.Workbook;
+
+import junit.framework.TestCase;
+
+public class TestXSSFFormulaEvaluation extends TestCase {
+    public TestXSSFFormulaEvaluation(String name) {
+               super(name);
+               
+               // Use system out logger
+           System.setProperty(
+                   "org.apache.poi.util.POILogger",
+                   "org.apache.poi.util.SystemOutLogger"
+           );
+       }
+
+    public void testSimpleArithmatic() throws Exception {
+       Workbook wb = new XSSFWorkbook();
+       Sheet s = wb.createSheet();
+       Row r = s.createRow(0);
+       
+       Cell c1 = r.createCell(0);
+       c1.setCellFormula("1+5");
+       assertTrue( Double.isNaN(c1.getNumericCellValue()) );
+       
+       Cell c2 = r.createCell(1);
+       c2.setCellFormula("10/2");
+       assertTrue( Double.isNaN(c2.getNumericCellValue()) );
+       
+       FormulaEvaluator fe = new FormulaEvaluator(s, wb);
+       fe.setCurrentRow(r);
+       
+       fe.evaluateFormulaCell(c1);
+       fe.evaluateFormulaCell(c2);
+       
+       assertEquals(6.0, c1.getNumericCellValue(), 0.0001);
+       assertEquals(5.0, c2.getNumericCellValue(), 0.0001);
+    }
+    
+    public void testSumCount() throws Exception {
+       Workbook wb = new XSSFWorkbook();
+       Sheet s = wb.createSheet();
+       Row r = s.createRow(0);
+       r.createCell(0).setCellValue(2.5);
+       r.createCell(1).setCellValue(1.1);
+       r.createCell(2).setCellValue(3.2);
+       r.createCell(4).setCellValue(10.7);
+       
+       r = s.createRow(1);
+       
+       Cell c1 = r.createCell(0);
+       c1.setCellFormula("SUM(A1:B1)");
+       assertTrue( Double.isNaN(c1.getNumericCellValue()) );
+       
+       Cell c2 = r.createCell(1);
+       c2.setCellFormula("SUM(A1:E1)");
+       assertTrue( Double.isNaN(c2.getNumericCellValue()) );
+       
+       Cell c3 = r.createCell(2);
+       c3.setCellFormula("COUNT(A1:A1)");
+       assertTrue( Double.isNaN(c3.getNumericCellValue()) );
+
+       Cell c4 = r.createCell(2);
+       c4.setCellFormula("COUNTA(A1:E1)");
+       assertTrue( Double.isNaN(c4.getNumericCellValue()) );
+
+
+       // Evaluate and test
+       FormulaEvaluator fe = new FormulaEvaluator(s, wb);
+       fe.setCurrentRow(r);
+       
+       fe.evaluateFormulaCell(c1);
+       fe.evaluateFormulaCell(c2);
+       fe.evaluateFormulaCell(c3);
+       fe.evaluateFormulaCell(c4);
+       
+       assertEquals(3.6, c1.getNumericCellValue(), 0.0001);
+       assertEquals(17.5, c2.getNumericCellValue(), 0.0001);
+       assertEquals(1, c3.getNumericCellValue(), 0.0001);
+       assertEquals(4, c4.getNumericCellValue(), 0.0001);
+    }
+}