*/
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
*
* @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);
*
* @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);
/**
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;
}
public short getCellNum() {
- return this.cellNum;
+ return (short)this.cellNum;
}
public CellStyle getCellStyle() {
}
+ public void setCellNum(int num) {
+ setCellNum((short)num);
+ }
public void setCellNum(short num) {
checkBounds(num);
this.cellNum = num;
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.
* @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);
}
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) {
--- /dev/null
+/* ====================================================================
+ 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);
+ }
+}