diff --git a/src/java/org/apache/poi/hssf/record/DVRecord.java b/src/java/org/apache/poi/hssf/record/DVRecord.java index c5839e2ab..980e4eeb7 100644 --- a/src/java/org/apache/poi/hssf/record/DVRecord.java +++ b/src/java/org/apache/poi/hssf/record/DVRecord.java @@ -18,9 +18,9 @@ package org.apache.poi.hssf.record; import org.apache.poi.hssf.record.common.UnicodeString; -import org.apache.poi.ss.formula.ptg.Ptg; import org.apache.poi.hssf.usermodel.HSSFDataValidation; import org.apache.poi.ss.formula.Formula; +import org.apache.poi.ss.formula.ptg.Ptg; import org.apache.poi.ss.util.CellRangeAddress; import org.apache.poi.ss.util.CellRangeAddressList; import org.apache.poi.util.BitField; @@ -196,8 +196,29 @@ public final class DVRecord extends StandardRecord { } // <-- end option flags + public String getPromptTitle() { + return resolveTitleString(_promptTitle); + } + public String getErrorTitle() { + return resolveTitleString(_errorTitle); + } + public String getPromptText() { + return resolveTitleString(_promptText); + } + + public String getErrorText() { + return resolveTitleString(_errorText); + } + + public Ptg[] getFormula1() { + return Formula.getTokens(_formula1); + } + + public Ptg[] getFormula2() { + return Formula.getTokens(_formula2); + } public CellRangeAddressList getCellRangeAddress() { return this._regions; @@ -284,7 +305,14 @@ public final class DVRecord extends StandardRecord { } return new UnicodeString(str); } - + + private static String resolveTitleString(UnicodeString us) { + if (us == null || us.equals(NULL_TEXT_STRING)) { + return null; + } + return us.getString(); + } + private static UnicodeString readUnicodeString(RecordInputStream in) { return new UnicodeString(in); } diff --git a/src/java/org/apache/poi/hssf/usermodel/DVConstraint.java b/src/java/org/apache/poi/hssf/usermodel/DVConstraint.java index a222b3857..8b6f56418 100644 --- a/src/java/org/apache/poi/hssf/usermodel/DVConstraint.java +++ b/src/java/org/apache/poi/hssf/usermodel/DVConstraint.java @@ -17,15 +17,20 @@ package org.apache.poi.hssf.usermodel; +import java.text.MessageFormat; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.Date; +import java.util.regex.Pattern; import org.apache.poi.hssf.model.HSSFFormulaParser; +import org.apache.poi.hssf.record.DVRecord; +import org.apache.poi.ss.formula.FormulaRenderer; +import org.apache.poi.ss.formula.FormulaRenderingWorkbook; +import org.apache.poi.ss.formula.FormulaType; import org.apache.poi.ss.formula.ptg.NumberPtg; import org.apache.poi.ss.formula.ptg.Ptg; import org.apache.poi.ss.formula.ptg.StringPtg; -import org.apache.poi.ss.formula.FormulaType; import org.apache.poi.ss.usermodel.DataValidationConstraint; /** @@ -429,4 +434,78 @@ public class DVConstraint implements DataValidationConstraint { HSSFWorkbook wb = sheet.getWorkbook(); return HSSFFormulaParser.parse(formula, wb, FormulaType.CELL, wb.getSheetIndex(sheet)); } + + static DVConstraint createDVConstraint(DVRecord dvRecord, FormulaRenderingWorkbook book) { + switch (dvRecord.getDataType()) { + case ValidationType.ANY: + return new DVConstraint(ValidationType.ANY, dvRecord.getConditionOperator(), null, null, null, null, null); + case ValidationType.INTEGER: + case ValidationType.DECIMAL: + case ValidationType.DATE: + case ValidationType.TIME: + case ValidationType.TEXT_LENGTH: + FormulaValuePair pair1 = toFormulaString(dvRecord.getFormula1(), book); + FormulaValuePair pair2 = toFormulaString(dvRecord.getFormula2(), book); + return new DVConstraint(dvRecord.getDataType(), dvRecord.getConditionOperator(), pair1.formula(), + pair2.formula(), pair1.value(), pair2.value(), null); + case ValidationType.LIST: + if (dvRecord.getListExplicitFormula()) { + String values = toFormulaString(dvRecord.getFormula1(), book).string(); + if (values.startsWith("\"")) { + values = values.substring(1); + } + if (values.endsWith("\"")) { + values = values.substring(0, values.length() - 1); + } + String[] explicitListValues = values.split(Pattern.quote("\0")); + return createExplicitListConstraint(explicitListValues); + } else { + String listFormula = toFormulaString(dvRecord.getFormula1(), book).string(); + return createFormulaListConstraint(listFormula); + } + case ValidationType.FORMULA: + return createCustomFormulaConstraint(toFormulaString(dvRecord.getFormula1(), book).string()); + default: + throw new UnsupportedOperationException(MessageFormat.format("validationType={0}", dvRecord.getDataType())); + } + } + + private static class FormulaValuePair { + private String _formula; + private String _value; + + public String formula() { + return _formula; + } + + public Double value() { + if (_value == null) { + return null; + } + return new Double(_value); + } + + public String string() { + if (_formula != null) { + return _formula; + } + if (_value != null) { + return _value; + } + return null; + } + } + + private static FormulaValuePair toFormulaString(Ptg[] ptgs, FormulaRenderingWorkbook book) { + FormulaValuePair pair = new FormulaValuePair(); + if (ptgs != null && ptgs.length > 0) { + String string = FormulaRenderer.toFormulaString(book, ptgs); + if (ptgs.length == 1 && ptgs[0].getClass() == NumberPtg.class) { + pair._value = string; + } else { + pair._formula = string; + } + } + return pair; + } } diff --git a/src/java/org/apache/poi/hssf/usermodel/HSSFSheet.java b/src/java/org/apache/poi/hssf/usermodel/HSSFSheet.java index ff33868c5..ce09d8012 100644 --- a/src/java/org/apache/poi/hssf/usermodel/HSSFSheet.java +++ b/src/java/org/apache/poi/hssf/usermodel/HSSFSheet.java @@ -44,6 +44,7 @@ import org.apache.poi.hssf.record.WSBoolRecord; import org.apache.poi.hssf.record.WindowTwoRecord; import org.apache.poi.hssf.record.aggregates.DataValidityTable; import org.apache.poi.hssf.record.aggregates.FormulaRecordAggregate; +import org.apache.poi.hssf.record.aggregates.RecordAggregate.RecordVisitor; import org.apache.poi.hssf.record.aggregates.WorksheetProtectionBlock; import org.apache.poi.hssf.util.PaneInformation; import org.apache.poi.ss.SpreadsheetVersion; @@ -60,6 +61,7 @@ import org.apache.poi.ss.usermodel.DataValidation; import org.apache.poi.ss.usermodel.DataValidationHelper; import org.apache.poi.ss.usermodel.Row; import org.apache.poi.ss.util.CellRangeAddress; +import org.apache.poi.ss.util.CellRangeAddressList; import org.apache.poi.ss.util.CellReference; import org.apache.poi.ss.util.SSCellRange; import org.apache.poi.ss.util.SheetUtil; @@ -394,6 +396,35 @@ public final class HSSFSheet implements org.apache.poi.ss.usermodel.Sheet { return _lastrow; } + public List getDataValidations() { + DataValidityTable dvt = _sheet.getOrCreateDataValidityTable(); + final List hssfValidations = new ArrayList(); + RecordVisitor visitor = new RecordVisitor() { + private HSSFEvaluationWorkbook book = HSSFEvaluationWorkbook.create(getWorkbook()); + + @Override + public void visitRecord(Record r) { + if (!(r instanceof DVRecord)) { + return; + } + DVRecord dvRecord = (DVRecord) r; + CellRangeAddressList regions = dvRecord.getCellRangeAddress().copy(); + DVConstraint constraint = DVConstraint.createDVConstraint(dvRecord, book); + HSSFDataValidation hssfDataValidation = new HSSFDataValidation(regions, constraint); + hssfDataValidation.setErrorStyle(dvRecord.getErrorStyle()); + hssfDataValidation.setEmptyCellAllowed(dvRecord.getEmptyCellAllowed()); + hssfDataValidation.setSuppressDropDownArrow(dvRecord.getSuppressDropdownArrow()); + hssfDataValidation.createPromptBox(dvRecord.getPromptTitle(), dvRecord.getPromptText()); + hssfDataValidation.setShowPromptBox(dvRecord.getShowPromptOnCellSelected()); + hssfDataValidation.createErrorBox(dvRecord.getErrorTitle(), dvRecord.getErrorText()); + hssfDataValidation.setShowErrorBox(dvRecord.getShowErrorOnInvalidValue()); + hssfValidations.add(hssfDataValidation); + } + }; + dvt.visitContainedRecords(visitor); + return hssfValidations; + } + /** * Creates a data validation object * diff --git a/src/java/org/apache/poi/ss/usermodel/Sheet.java b/src/java/org/apache/poi/ss/usermodel/Sheet.java index 1ca2ccfad..57c8785c6 100644 --- a/src/java/org/apache/poi/ss/usermodel/Sheet.java +++ b/src/java/org/apache/poi/ss/usermodel/Sheet.java @@ -18,6 +18,7 @@ package org.apache.poi.ss.usermodel; import java.util.Iterator; +import java.util.List; import org.apache.poi.hssf.util.PaneInformation; import org.apache.poi.ss.util.CellRangeAddress; @@ -921,6 +922,12 @@ public interface Sheet extends Iterable { public DataValidationHelper getDataValidationHelper(); + /** + * Returns the list of DataValidation in the sheet. + * @return list of DataValidation in the sheet + */ + public List getDataValidations(); + /** * Creates a data validation object * @param dataValidation The Data validation object settings diff --git a/src/ooxml/java/org/apache/poi/xssf/streaming/SXSSFSheet.java b/src/ooxml/java/org/apache/poi/xssf/streaming/SXSSFSheet.java index 080d31fc3..d676eb599 100644 --- a/src/ooxml/java/org/apache/poi/xssf/streaming/SXSSFSheet.java +++ b/src/ooxml/java/org/apache/poi/xssf/streaming/SXSSFSheet.java @@ -20,6 +20,7 @@ package org.apache.poi.xssf.streaming; import java.io.IOException; import java.io.InputStream; import java.util.Iterator; +import java.util.List; import java.util.Map; import java.util.TreeMap; @@ -42,6 +43,7 @@ import org.apache.poi.ss.usermodel.SheetConditionalFormatting; import org.apache.poi.ss.usermodel.Workbook; import org.apache.poi.ss.util.CellRangeAddress; import org.apache.poi.ss.util.SheetUtil; +import org.apache.poi.xssf.usermodel.XSSFDataValidation; import org.apache.poi.xssf.usermodel.XSSFSheet; import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTSheetFormatPr; import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTWorksheet; @@ -1339,6 +1341,11 @@ public class SXSSFSheet implements Sheet, Cloneable return _sh.getDataValidationHelper(); } + public List getDataValidations() + { + return _sh.getDataValidations(); + } + /** * Creates a data validation object * @param dataValidation The Data validation object settings diff --git a/src/testcases/org/apache/poi/hssf/usermodel/TestDataValidation.java b/src/testcases/org/apache/poi/hssf/usermodel/TestDataValidation.java index b0e03cb71..1d71ca5c6 100644 --- a/src/testcases/org/apache/poi/hssf/usermodel/TestDataValidation.java +++ b/src/testcases/org/apache/poi/hssf/usermodel/TestDataValidation.java @@ -24,6 +24,7 @@ import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.PrintStream; +import java.util.List; import junit.framework.AssertionFailedError; @@ -34,7 +35,16 @@ import org.apache.poi.hssf.eventmodel.EventRecordFactory; import org.apache.poi.hssf.record.DVRecord; import org.apache.poi.hssf.record.RecordFormatException; import org.apache.poi.poifs.filesystem.POIFSFileSystem; -import org.apache.poi.ss.usermodel.*; +import org.apache.poi.ss.usermodel.BaseTestDataValidation; +import org.apache.poi.ss.usermodel.DataValidation; +import org.apache.poi.ss.usermodel.DataValidationConstraint; +import org.apache.poi.ss.usermodel.DataValidationConstraint.OperatorType; +import org.apache.poi.ss.usermodel.DataValidationConstraint.ValidationType; +import org.apache.poi.ss.usermodel.DataValidationHelper; +import org.apache.poi.ss.usermodel.DateUtil; +import org.apache.poi.ss.usermodel.Sheet; +import org.apache.poi.ss.usermodel.Workbook; +import org.apache.poi.ss.util.CellRangeAddress; import org.apache.poi.ss.util.CellRangeAddressList; /** @@ -209,4 +219,236 @@ public final class TestDataValidation extends BaseTestDataValidation { } return -1; } + + public void testGetDataValidationsAny() { + HSSFWorkbook wb = new HSSFWorkbook(); + HSSFSheet sheet = wb.createSheet(); + List list = sheet.getDataValidations(); + assertEquals(0, list.size()); + + DataValidationHelper dataValidationHelper = sheet.getDataValidationHelper(); + DataValidationConstraint constraint = dataValidationHelper.createNumericConstraint(ValidationType.ANY, + OperatorType.IGNORED, null, null); + CellRangeAddressList addressList = new CellRangeAddressList(1, 2, 3, 4); + DataValidation validation = dataValidationHelper.createValidation(constraint, addressList); + validation.setEmptyCellAllowed(true); + validation.createErrorBox("error-title", "error-text"); + validation.createPromptBox("prompt-title", "prompt-text"); + sheet.addValidationData(validation); + + list = sheet.getDataValidations(); // <-- works + assertEquals(1, list.size()); + + HSSFDataValidation dv = list.get(0); + { + CellRangeAddressList regions = dv.getRegions(); + assertEquals(1, regions.countRanges()); + + CellRangeAddress address = regions.getCellRangeAddress(0); + assertEquals(1, address.getFirstRow()); + assertEquals(2, address.getLastRow()); + assertEquals(3, address.getFirstColumn()); + assertEquals(4, address.getLastColumn()); + } + assertEquals(true, dv.getEmptyCellAllowed()); + assertEquals(false, dv.getSuppressDropDownArrow()); + assertEquals(true, dv.getShowErrorBox()); + assertEquals("error-title", dv.getErrorBoxTitle()); + assertEquals("error-text", dv.getErrorBoxText()); + assertEquals(true, dv.getShowPromptBox()); + assertEquals("prompt-title", dv.getPromptBoxTitle()); + assertEquals("prompt-text", dv.getPromptBoxText()); + + DataValidationConstraint c = dv.getValidationConstraint(); + assertEquals(ValidationType.ANY, c.getValidationType()); + assertEquals(OperatorType.IGNORED, c.getOperator()); + } + + public void testGetDataValidationsIntegerFormula() { + HSSFWorkbook wb = new HSSFWorkbook(); + HSSFSheet sheet = wb.createSheet(); + List list = sheet.getDataValidations(); + assertEquals(0, list.size()); + + DataValidationHelper dataValidationHelper = sheet.getDataValidationHelper(); + DataValidationConstraint constraint = dataValidationHelper.createIntegerConstraint(OperatorType.BETWEEN, "=A2", + "=A3"); + CellRangeAddressList addressList = new CellRangeAddressList(0, 0, 0, 0); + DataValidation validation = dataValidationHelper.createValidation(constraint, addressList); + sheet.addValidationData(validation); + + list = sheet.getDataValidations(); // <-- works + assertEquals(1, list.size()); + + HSSFDataValidation dv = list.get(0); + DVConstraint c = dv.getConstraint(); + assertEquals(ValidationType.INTEGER, c.getValidationType()); + assertEquals(OperatorType.BETWEEN, c.getOperator()); + assertEquals("A2", c.getFormula1()); + assertEquals("A3", c.getFormula2()); + assertEquals(null, c.getValue1()); + assertEquals(null, c.getValue2()); + } + + public void testGetDataValidationsIntegerValue() { + HSSFWorkbook wb = new HSSFWorkbook(); + HSSFSheet sheet = wb.createSheet(); + List list = sheet.getDataValidations(); + assertEquals(0, list.size()); + + DataValidationHelper dataValidationHelper = sheet.getDataValidationHelper(); + DataValidationConstraint constraint = dataValidationHelper.createIntegerConstraint(OperatorType.BETWEEN, "100", + "200"); + CellRangeAddressList addressList = new CellRangeAddressList(0, 0, 0, 0); + DataValidation validation = dataValidationHelper.createValidation(constraint, addressList); + sheet.addValidationData(validation); + + list = sheet.getDataValidations(); // <-- works + assertEquals(1, list.size()); + + HSSFDataValidation dv = list.get(0); + DVConstraint c = dv.getConstraint(); + assertEquals(ValidationType.INTEGER, c.getValidationType()); + assertEquals(OperatorType.BETWEEN, c.getOperator()); + assertEquals(null, c.getFormula1()); + assertEquals(null, c.getFormula2()); + assertEquals(new Double("100"), c.getValue1()); + assertEquals(new Double("200"), c.getValue2()); + } + + public void testGetDataValidationsDecimal() { + HSSFWorkbook wb = new HSSFWorkbook(); + HSSFSheet sheet = wb.createSheet(); + List list = sheet.getDataValidations(); + assertEquals(0, list.size()); + + DataValidationHelper dataValidationHelper = sheet.getDataValidationHelper(); + DataValidationConstraint constraint = dataValidationHelper.createDecimalConstraint(OperatorType.BETWEEN, "=A2", + "200"); + CellRangeAddressList addressList = new CellRangeAddressList(0, 0, 0, 0); + DataValidation validation = dataValidationHelper.createValidation(constraint, addressList); + sheet.addValidationData(validation); + + list = sheet.getDataValidations(); // <-- works + assertEquals(1, list.size()); + + HSSFDataValidation dv = list.get(0); + DVConstraint c = dv.getConstraint(); + assertEquals(ValidationType.DECIMAL, c.getValidationType()); + assertEquals(OperatorType.BETWEEN, c.getOperator()); + assertEquals("A2", c.getFormula1()); + assertEquals(null, c.getFormula2()); + assertEquals(null, c.getValue1()); + assertEquals(new Double("200"), c.getValue2()); + } + + public void testGetDataValidationsDate() { + HSSFWorkbook wb = new HSSFWorkbook(); + HSSFSheet sheet = wb.createSheet(); + List list = sheet.getDataValidations(); + assertEquals(0, list.size()); + + DataValidationHelper dataValidationHelper = sheet.getDataValidationHelper(); + DataValidationConstraint constraint = dataValidationHelper.createDateConstraint(OperatorType.EQUAL, + "2014/10/25", null, null); + CellRangeAddressList addressList = new CellRangeAddressList(0, 0, 0, 0); + DataValidation validation = dataValidationHelper.createValidation(constraint, addressList); + sheet.addValidationData(validation); + + list = sheet.getDataValidations(); // <-- works + assertEquals(1, list.size()); + + HSSFDataValidation dv = list.get(0); + DVConstraint c = dv.getConstraint(); + assertEquals(ValidationType.DATE, c.getValidationType()); + assertEquals(OperatorType.EQUAL, c.getOperator()); + assertEquals(null, c.getFormula1()); + assertEquals(null, c.getFormula2()); + assertEquals(DateUtil.getExcelDate(DateUtil.parseYYYYMMDDDate("2014/10/25")), c.getValue1()); + assertEquals(null, c.getValue2()); + } + + public void testGetDataValidationsListExplicit() { + HSSFWorkbook wb = new HSSFWorkbook(); + HSSFSheet sheet = wb.createSheet(); + List list = sheet.getDataValidations(); + assertEquals(0, list.size()); + + DataValidationHelper dataValidationHelper = sheet.getDataValidationHelper(); + DataValidationConstraint constraint = dataValidationHelper.createExplicitListConstraint(new String[] { "aaa", + "bbb", "ccc" }); + CellRangeAddressList addressList = new CellRangeAddressList(0, 0, 0, 0); + DataValidation validation = dataValidationHelper.createValidation(constraint, addressList); + validation.setSuppressDropDownArrow(true); + sheet.addValidationData(validation); + + list = sheet.getDataValidations(); // <-- works + assertEquals(1, list.size()); + + HSSFDataValidation dv = list.get(0); + assertEquals(true, dv.getSuppressDropDownArrow()); + + DVConstraint c = dv.getConstraint(); + assertEquals(ValidationType.LIST, c.getValidationType()); + assertEquals(null, c.getFormula1()); + assertEquals(null, c.getFormula2()); + assertEquals(null, c.getValue1()); + assertEquals(null, c.getValue2()); + String[] values = c.getExplicitListValues(); + assertEquals(3, values.length); + assertEquals("aaa", values[0]); + assertEquals("bbb", values[1]); + assertEquals("ccc", values[2]); + } + + public void testGetDataValidationsListFormula() { + HSSFWorkbook wb = new HSSFWorkbook(); + HSSFSheet sheet = wb.createSheet(); + List list = sheet.getDataValidations(); + assertEquals(0, list.size()); + + DataValidationHelper dataValidationHelper = sheet.getDataValidationHelper(); + DataValidationConstraint constraint = dataValidationHelper.createFormulaListConstraint("A2"); + CellRangeAddressList addressList = new CellRangeAddressList(0, 0, 0, 0); + DataValidation validation = dataValidationHelper.createValidation(constraint, addressList); + validation.setSuppressDropDownArrow(true); + sheet.addValidationData(validation); + + list = sheet.getDataValidations(); // <-- works + assertEquals(1, list.size()); + + HSSFDataValidation dv = list.get(0); + assertEquals(true, dv.getSuppressDropDownArrow()); + + DVConstraint c = dv.getConstraint(); + assertEquals(ValidationType.LIST, c.getValidationType()); + assertEquals("A2", c.getFormula1()); + assertEquals(null, c.getFormula2()); + assertEquals(null, c.getValue1()); + assertEquals(null, c.getValue2()); + } + + public void testGetDataValidationsFormula() { + HSSFWorkbook wb = new HSSFWorkbook(); + HSSFSheet sheet = wb.createSheet(); + List list = sheet.getDataValidations(); + assertEquals(0, list.size()); + + DataValidationHelper dataValidationHelper = sheet.getDataValidationHelper(); + DataValidationConstraint constraint = dataValidationHelper.createCustomConstraint("A2:A3"); + CellRangeAddressList addressList = new CellRangeAddressList(0, 0, 0, 0); + DataValidation validation = dataValidationHelper.createValidation(constraint, addressList); + sheet.addValidationData(validation); + + list = sheet.getDataValidations(); // <-- works + assertEquals(1, list.size()); + + HSSFDataValidation dv = list.get(0); + DVConstraint c = dv.getConstraint(); + assertEquals(ValidationType.FORMULA, c.getValidationType()); + assertEquals("A2:A3", c.getFormula1()); + assertEquals(null, c.getFormula2()); + assertEquals(null, c.getValue1()); + assertEquals(null, c.getValue2()); + } }