Complete evaluation support for multi-sheet references for bug #55906
git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@1613467 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
parent
2438213bd8
commit
59861b7836
@ -17,6 +17,7 @@
|
|||||||
|
|
||||||
package org.apache.poi.ss.formula.functions;
|
package org.apache.poi.ss.formula.functions;
|
||||||
|
|
||||||
|
import org.apache.poi.ss.formula.ThreeDEval;
|
||||||
import org.apache.poi.ss.formula.TwoDEval;
|
import org.apache.poi.ss.formula.TwoDEval;
|
||||||
import org.apache.poi.ss.formula.eval.RefEval;
|
import org.apache.poi.ss.formula.eval.RefEval;
|
||||||
import org.apache.poi.ss.formula.eval.ValueEval;
|
import org.apache.poi.ss.formula.eval.ValueEval;
|
||||||
@ -45,14 +46,15 @@ final class CountUtils {
|
|||||||
/**
|
/**
|
||||||
* @return the number of evaluated cells in the range that match the specified criteria
|
* @return the number of evaluated cells in the range that match the specified criteria
|
||||||
*/
|
*/
|
||||||
public static int countMatchingCellsInArea(TwoDEval areaEval, I_MatchPredicate criteriaPredicate) {
|
public static int countMatchingCellsInArea(ThreeDEval areaEval, I_MatchPredicate criteriaPredicate) {
|
||||||
int result = 0;
|
int result = 0;
|
||||||
|
|
||||||
|
for (int sIx=areaEval.getFirstSheetIndex(); sIx <= areaEval.getLastSheetIndex(); sIx++) {
|
||||||
int height = areaEval.getHeight();
|
int height = areaEval.getHeight();
|
||||||
int width = areaEval.getWidth();
|
int width = areaEval.getWidth();
|
||||||
for (int rrIx=0; rrIx<height; rrIx++) {
|
for (int rrIx=0; rrIx<height; rrIx++) {
|
||||||
for (int rcIx=0; rcIx<width; rcIx++) {
|
for (int rcIx=0; rcIx<width; rcIx++) {
|
||||||
ValueEval ve = areaEval.getValue(rrIx, rcIx);
|
ValueEval ve = areaEval.getValue(sIx, rrIx, rcIx);
|
||||||
|
|
||||||
if(criteriaPredicate instanceof I_MatchAreaPredicate){
|
if(criteriaPredicate instanceof I_MatchAreaPredicate){
|
||||||
I_MatchAreaPredicate areaPredicate = (I_MatchAreaPredicate)criteriaPredicate;
|
I_MatchAreaPredicate areaPredicate = (I_MatchAreaPredicate)criteriaPredicate;
|
||||||
@ -64,6 +66,7 @@ final class CountUtils {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
@ -84,8 +87,11 @@ final class CountUtils {
|
|||||||
if (eval == null) {
|
if (eval == null) {
|
||||||
throw new IllegalArgumentException("eval must not be null");
|
throw new IllegalArgumentException("eval must not be null");
|
||||||
}
|
}
|
||||||
|
if (eval instanceof ThreeDEval) {
|
||||||
|
return countMatchingCellsInArea((ThreeDEval) eval, criteriaPredicate);
|
||||||
|
}
|
||||||
if (eval instanceof TwoDEval) {
|
if (eval instanceof TwoDEval) {
|
||||||
return countMatchingCellsInArea((TwoDEval) eval, criteriaPredicate);
|
throw new IllegalArgumentException("Count requires 3D Evals, 2D ones aren't supported");
|
||||||
}
|
}
|
||||||
if (eval instanceof RefEval) {
|
if (eval instanceof RefEval) {
|
||||||
return CountUtils.countMatchingCellsInRef((RefEval) eval, criteriaPredicate);
|
return CountUtils.countMatchingCellsInRef((RefEval) eval, criteriaPredicate);
|
||||||
|
@ -17,7 +17,7 @@
|
|||||||
|
|
||||||
package org.apache.poi.ss.formula.functions;
|
package org.apache.poi.ss.formula.functions;
|
||||||
|
|
||||||
import org.apache.poi.ss.formula.TwoDEval;
|
import org.apache.poi.ss.formula.ThreeDEval;
|
||||||
import org.apache.poi.ss.formula.eval.BlankEval;
|
import org.apache.poi.ss.formula.eval.BlankEval;
|
||||||
import org.apache.poi.ss.formula.eval.NumberEval;
|
import org.apache.poi.ss.formula.eval.NumberEval;
|
||||||
import org.apache.poi.ss.formula.eval.RefEval;
|
import org.apache.poi.ss.formula.eval.RefEval;
|
||||||
@ -42,8 +42,8 @@ public final class Countblank extends Fixed1ArgFunction {
|
|||||||
double result;
|
double result;
|
||||||
if (arg0 instanceof RefEval) {
|
if (arg0 instanceof RefEval) {
|
||||||
result = CountUtils.countMatchingCellsInRef((RefEval) arg0, predicate);
|
result = CountUtils.countMatchingCellsInRef((RefEval) arg0, predicate);
|
||||||
} else if (arg0 instanceof TwoDEval) {
|
} else if (arg0 instanceof ThreeDEval) {
|
||||||
result = CountUtils.countMatchingCellsInArea((TwoDEval) arg0, predicate);
|
result = CountUtils.countMatchingCellsInArea((ThreeDEval) arg0, predicate);
|
||||||
} else {
|
} else {
|
||||||
throw new IllegalArgumentException("Bad range arg type (" + arg0.getClass().getName() + ")");
|
throw new IllegalArgumentException("Bad range arg type (" + arg0.getClass().getName() + ")");
|
||||||
}
|
}
|
||||||
|
@ -19,7 +19,7 @@ package org.apache.poi.ss.formula.functions;
|
|||||||
|
|
||||||
import java.util.regex.Pattern;
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
import org.apache.poi.ss.formula.TwoDEval;
|
import org.apache.poi.ss.formula.ThreeDEval;
|
||||||
import org.apache.poi.ss.formula.eval.BlankEval;
|
import org.apache.poi.ss.formula.eval.BlankEval;
|
||||||
import org.apache.poi.ss.formula.eval.BoolEval;
|
import org.apache.poi.ss.formula.eval.BoolEval;
|
||||||
import org.apache.poi.ss.formula.eval.ErrorEval;
|
import org.apache.poi.ss.formula.eval.ErrorEval;
|
||||||
@ -445,8 +445,8 @@ public final class Countif extends Fixed2ArgFunction {
|
|||||||
|
|
||||||
if (rangeArg instanceof RefEval) {
|
if (rangeArg instanceof RefEval) {
|
||||||
return CountUtils.countMatchingCellsInRef((RefEval) rangeArg, criteriaPredicate);
|
return CountUtils.countMatchingCellsInRef((RefEval) rangeArg, criteriaPredicate);
|
||||||
} else if (rangeArg instanceof TwoDEval) {
|
} else if (rangeArg instanceof ThreeDEval) {
|
||||||
return CountUtils.countMatchingCellsInArea((TwoDEval) rangeArg, criteriaPredicate);
|
return CountUtils.countMatchingCellsInArea((ThreeDEval) rangeArg, criteriaPredicate);
|
||||||
} else {
|
} else {
|
||||||
throw new IllegalArgumentException("Bad range arg type (" + rangeArg.getClass().getName() + ")");
|
throw new IllegalArgumentException("Bad range arg type (" + rangeArg.getClass().getName() + ")");
|
||||||
}
|
}
|
||||||
|
@ -17,6 +17,7 @@
|
|||||||
|
|
||||||
package org.apache.poi.ss.formula.functions;
|
package org.apache.poi.ss.formula.functions;
|
||||||
|
|
||||||
|
import org.apache.poi.ss.formula.ThreeDEval;
|
||||||
import org.apache.poi.ss.formula.TwoDEval;
|
import org.apache.poi.ss.formula.TwoDEval;
|
||||||
import org.apache.poi.ss.formula.eval.BlankEval;
|
import org.apache.poi.ss.formula.eval.BlankEval;
|
||||||
import org.apache.poi.ss.formula.eval.BoolEval;
|
import org.apache.poi.ss.formula.eval.BoolEval;
|
||||||
@ -30,7 +31,6 @@ import org.apache.poi.ss.formula.eval.StringValueEval;
|
|||||||
import org.apache.poi.ss.formula.eval.ValueEval;
|
import org.apache.poi.ss.formula.eval.ValueEval;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Amol S. Deshmukh < amolweb at ya hoo dot com >
|
|
||||||
* This is the super class for all excel function evaluator
|
* This is the super class for all excel function evaluator
|
||||||
* classes that take variable number of operands, and
|
* classes that take variable number of operands, and
|
||||||
* where the order of operands does not matter
|
* where the order of operands does not matter
|
||||||
@ -141,7 +141,21 @@ public abstract class MultiOperandNumericFunction implements Function {
|
|||||||
* Collects values from a single argument
|
* Collects values from a single argument
|
||||||
*/
|
*/
|
||||||
private void collectValues(ValueEval operand, DoubleList temp) throws EvaluationException {
|
private void collectValues(ValueEval operand, DoubleList temp) throws EvaluationException {
|
||||||
|
if (operand instanceof ThreeDEval) {
|
||||||
|
ThreeDEval ae = (ThreeDEval) operand;
|
||||||
|
for (int sIx=ae.getFirstSheetIndex(); sIx <= ae.getLastSheetIndex(); sIx++) {
|
||||||
|
int width = ae.getWidth();
|
||||||
|
int height = ae.getHeight();
|
||||||
|
for (int rrIx=0; rrIx<height; rrIx++) {
|
||||||
|
for (int rcIx=0; rcIx<width; rcIx++) {
|
||||||
|
ValueEval ve = ae.getValue(sIx, rrIx, rcIx);
|
||||||
|
if(!isSubtotalCounted() && ae.isSubTotal(rrIx, rcIx)) continue;
|
||||||
|
collectValue(ve, true, temp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
if (operand instanceof TwoDEval) {
|
if (operand instanceof TwoDEval) {
|
||||||
TwoDEval ae = (TwoDEval) operand;
|
TwoDEval ae = (TwoDEval) operand;
|
||||||
int width = ae.getWidth();
|
int width = ae.getWidth();
|
||||||
|
@ -247,10 +247,8 @@ public final class TestXSSFFormulaEvaluation extends BaseTestFormulaEvaluator {
|
|||||||
* from Sheets 1 through Sheet 3).
|
* from Sheets 1 through Sheet 3).
|
||||||
* This test, based on common test files for HSSF and XSSF, checks
|
* This test, based on common test files for HSSF and XSSF, checks
|
||||||
* that we can correctly evaluate these
|
* that we can correctly evaluate these
|
||||||
*
|
|
||||||
* DISABLED pending support, see bug #55906
|
|
||||||
*/
|
*/
|
||||||
public void DISABLEDtestMultiSheetAreasHSSFandXSSF() throws Exception {
|
public void testMultiSheetAreasHSSFandXSSF() throws Exception {
|
||||||
Workbook[] wbs = new Workbook[] {
|
Workbook[] wbs = new Workbook[] {
|
||||||
HSSFTestDataSamples.openSampleWorkbook("55906-MultiSheetRefs.xls"),
|
HSSFTestDataSamples.openSampleWorkbook("55906-MultiSheetRefs.xls"),
|
||||||
XSSFTestDataSamples.openSampleWorkbook("55906-MultiSheetRefs.xlsx")
|
XSSFTestDataSamples.openSampleWorkbook("55906-MultiSheetRefs.xlsx")
|
||||||
@ -264,11 +262,11 @@ public final class TestXSSFFormulaEvaluation extends BaseTestFormulaEvaluator {
|
|||||||
Cell sumFA = s1.getRow(2).getCell(7);
|
Cell sumFA = s1.getRow(2).getCell(7);
|
||||||
assertNotNull(sumFA);
|
assertNotNull(sumFA);
|
||||||
assertEquals("SUM(Sheet1:Sheet3!A1:B2)", sumFA.getCellFormula());
|
assertEquals("SUM(Sheet1:Sheet3!A1:B2)", sumFA.getCellFormula());
|
||||||
assertEquals("110.0", evaluator.evaluate(sumFA).formatAsString());
|
assertEquals("Failed for " + wb.getClass(), "110.0", evaluator.evaluate(sumFA).formatAsString());
|
||||||
|
|
||||||
|
|
||||||
// Various Stats formulas on ranges of numbers
|
// Various Stats formulas on ranges of numbers
|
||||||
Cell avgFA = s1.getRow(2).getCell(7);
|
Cell avgFA = s1.getRow(2).getCell(8);
|
||||||
assertNotNull(avgFA);
|
assertNotNull(avgFA);
|
||||||
assertEquals("AVERAGE(Sheet1:Sheet3!A1:B2)", avgFA.getCellFormula());
|
assertEquals("AVERAGE(Sheet1:Sheet3!A1:B2)", avgFA.getCellFormula());
|
||||||
assertEquals("27.5", evaluator.evaluate(avgFA).formatAsString());
|
assertEquals("27.5", evaluator.evaluate(avgFA).formatAsString());
|
||||||
|
@ -116,9 +116,13 @@ public class TestNetworkdaysFunction extends TestCase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ValueEval getRelativeValue(int relativeRowIndex, int relativeColumnIndex) {
|
public ValueEval getRelativeValue(int sheetIndex, int relativeRowIndex, int relativeColumnIndex) {
|
||||||
return this.holidays.get(relativeColumnIndex);
|
return this.holidays.get(relativeColumnIndex);
|
||||||
}
|
}
|
||||||
|
@Override
|
||||||
|
public ValueEval getRelativeValue(int relativeRowIndex, int relativeColumnIndex) {
|
||||||
|
return getRelativeValue(-1, relativeRowIndex, relativeColumnIndex);
|
||||||
|
}
|
||||||
|
|
||||||
public AreaEval offset(int relFirstRowIx, int relLastRowIx, int relFirstColIx, int relLastColIx) {
|
public AreaEval offset(int relFirstRowIx, int relLastRowIx, int relFirstColIx, int relLastColIx) {
|
||||||
return null;
|
return null;
|
||||||
|
@ -159,9 +159,13 @@ public class TestWorkdayFunction extends TestCase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ValueEval getRelativeValue(int relativeRowIndex, int relativeColumnIndex) {
|
public ValueEval getRelativeValue(int sheetIndex, int relativeRowIndex, int relativeColumnIndex) {
|
||||||
return this.holidays.get(relativeColumnIndex);
|
return this.holidays.get(relativeColumnIndex);
|
||||||
}
|
}
|
||||||
|
@Override
|
||||||
|
public ValueEval getRelativeValue(int relativeRowIndex, int relativeColumnIndex) {
|
||||||
|
return getRelativeValue(-1, relativeRowIndex, relativeColumnIndex);
|
||||||
|
}
|
||||||
|
|
||||||
public AreaEval offset(int relFirstRowIx, int relLastRowIx, int relFirstColIx, int relLastColIx) {
|
public AreaEval offset(int relFirstRowIx, int relLastRowIx, int relFirstColIx, int relLastColIx) {
|
||||||
return null;
|
return null;
|
||||||
|
@ -96,6 +96,9 @@ public final class TestRangeEval extends TestCase {
|
|||||||
public ValueEval getRelativeValue(int relativeRowIndex, int relativeColumnIndex) {
|
public ValueEval getRelativeValue(int relativeRowIndex, int relativeColumnIndex) {
|
||||||
throw new RuntimeException("not expected to be called during this test");
|
throw new RuntimeException("not expected to be called during this test");
|
||||||
}
|
}
|
||||||
|
public ValueEval getRelativeValue(int sheetIndex, int relativeRowIndex, int relativeColumnIndex) {
|
||||||
|
throw new RuntimeException("not expected to be called during this test");
|
||||||
|
}
|
||||||
public AreaEval offset(int relFirstRowIx, int relLastRowIx, int relFirstColIx,
|
public AreaEval offset(int relFirstRowIx, int relLastRowIx, int relFirstColIx,
|
||||||
int relLastColIx) {
|
int relLastColIx) {
|
||||||
AreaI area = new OffsetArea(getFirstRow(), getFirstColumn(),
|
AreaI area = new OffsetArea(getFirstRow(), getFirstColumn(),
|
||||||
|
@ -89,6 +89,9 @@ public final class EvalFactory {
|
|||||||
_values = values;
|
_values = values;
|
||||||
}
|
}
|
||||||
public ValueEval getRelativeValue(int relativeRowIndex, int relativeColumnIndex) {
|
public ValueEval getRelativeValue(int relativeRowIndex, int relativeColumnIndex) {
|
||||||
|
return getRelativeValue(-1, relativeRowIndex, relativeColumnIndex);
|
||||||
|
}
|
||||||
|
public ValueEval getRelativeValue(int sheetIndex, int relativeRowIndex, int relativeColumnIndex) {
|
||||||
if (relativeRowIndex < 0 || relativeRowIndex >=getHeight()) {
|
if (relativeRowIndex < 0 || relativeRowIndex >=getHeight()) {
|
||||||
throw new IllegalArgumentException("row index out of range");
|
throw new IllegalArgumentException("row index out of range");
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user