From 11bee1ebf94271ba18b7ba36e95e317b42ee3864 Mon Sep 17 00:00:00 2001 From: David North Date: Wed, 13 Jan 2016 17:54:24 +0000 Subject: [PATCH] Generalised API for adding ignored errors, e.g. number stored as text. https://bz.apache.org/bugzilla/show_bug.cgi?id=56892 git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@1724469 13f79535-47bb-0310-9956-ffa450edef68 --- .../poi/xssf/usermodel/IgnoredErrorType.java | 106 +++++++++++++++++ .../apache/poi/xssf/usermodel/XSSFSheet.java | 110 +++++++++++------- .../poi/xssf/usermodel/TestXSSFSheet.java | 73 ++++++++++++ 3 files changed, 248 insertions(+), 41 deletions(-) create mode 100644 src/ooxml/java/org/apache/poi/xssf/usermodel/IgnoredErrorType.java diff --git a/src/ooxml/java/org/apache/poi/xssf/usermodel/IgnoredErrorType.java b/src/ooxml/java/org/apache/poi/xssf/usermodel/IgnoredErrorType.java new file mode 100644 index 0000000000..335d578838 --- /dev/null +++ b/src/ooxml/java/org/apache/poi/xssf/usermodel/IgnoredErrorType.java @@ -0,0 +1,106 @@ +/* ==================================================================== + 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.openxmlformats.schemas.spreadsheetml.x2006.main.CTIgnoredError; + +/** + * Types of ignored error. + */ +public enum IgnoredErrorType { + + CALCULATED_COLUMN, + + EMPTY_CELL_REFERENCE, + + EVALUATION_ERROR, + + FORMULA, + + FORMULA_RANGE, + + LIST_DATA_VALIDATION, + + NUMBER_STORED_AS_TEXT, + + TWO_DIGIT_TEXT_YEAR, + + UNLOCKED_FORMULA; + + // Methods below are not part of the public API + + boolean isSet(CTIgnoredError error) { + switch(this) { + case CALCULATED_COLUMN: + return error.isSetCalculatedColumn(); + case EMPTY_CELL_REFERENCE: + return error.isSetEmptyCellReference(); + case EVALUATION_ERROR: + return error.isSetEvalError(); + case FORMULA: + return error.isSetFormula(); + case FORMULA_RANGE: + return error.isSetFormulaRange(); + case LIST_DATA_VALIDATION: + return error.isSetListDataValidation(); + case NUMBER_STORED_AS_TEXT: + return error.isSetNumberStoredAsText(); + case TWO_DIGIT_TEXT_YEAR: + return error.isSetTwoDigitTextYear(); + case UNLOCKED_FORMULA: + return error.isSetUnlockedFormula(); + default: + throw new IllegalStateException(); + } + } + + void set(CTIgnoredError error) { + switch(this) { + case CALCULATED_COLUMN: + error.setCalculatedColumn(true); + break; + case EMPTY_CELL_REFERENCE: + error.setEmptyCellReference(true); + break; + case EVALUATION_ERROR: + error.setEvalError(true); + break; + case FORMULA: + error.setFormula(true); + break; + case FORMULA_RANGE: + error.setFormulaRange(true); + break; + case LIST_DATA_VALIDATION: + error.setListDataValidation(true); + break; + case NUMBER_STORED_AS_TEXT: + error.setNumberStoredAsText(true); + break; + case TWO_DIGIT_TEXT_YEAR: + error.setTwoDigitTextYear(true); + break; + case UNLOCKED_FORMULA: + error.setUnlockedFormula(true); + break; + default: + throw new IllegalStateException(); + } + } + +} diff --git a/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFSheet.java b/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFSheet.java index fa8d85b261..c0ea0681a7 100644 --- a/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFSheet.java +++ b/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFSheet.java @@ -31,8 +31,11 @@ import java.util.Collections; import java.util.Comparator; import java.util.HashMap; import java.util.Iterator; +import java.util.LinkedHashMap; +import java.util.LinkedHashSet; import java.util.List; import java.util.Map; +import java.util.Set; import java.util.SortedMap; import java.util.TreeMap; @@ -78,47 +81,7 @@ import org.apache.poi.xssf.usermodel.helpers.ColumnHelper; import org.apache.poi.xssf.usermodel.helpers.XSSFRowShifter; import org.apache.xmlbeans.XmlException; import org.apache.xmlbeans.XmlOptions; -import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTAutoFilter; -import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTBreak; -import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTCalcPr; -import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTCell; -import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTCellFormula; -import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTCol; -import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTColor; -import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTCols; -import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTComment; -import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTCommentList; -import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTDataValidation; -import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTDataValidations; -import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTDrawing; -import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTHeaderFooter; -import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTHyperlink; -import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTLegacyDrawing; -import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTMergeCell; -import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTMergeCells; -import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTOutlinePr; -import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTPageBreak; -import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTPageMargins; -import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTPageSetUpPr; -import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTPane; -import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTPrintOptions; -import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTRow; -import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTSelection; -import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTSheet; -import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTSheetCalcPr; -import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTSheetFormatPr; -import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTSheetPr; -import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTSheetProtection; -import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTSheetView; -import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTSheetViews; -import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTTablePart; -import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTTableParts; -import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTWorksheet; -import org.openxmlformats.schemas.spreadsheetml.x2006.main.STCalcMode; -import org.openxmlformats.schemas.spreadsheetml.x2006.main.STCellFormulaType; -import org.openxmlformats.schemas.spreadsheetml.x2006.main.STPane; -import org.openxmlformats.schemas.spreadsheetml.x2006.main.STPaneState; -import org.openxmlformats.schemas.spreadsheetml.x2006.main.WorksheetDocument; +import org.openxmlformats.schemas.spreadsheetml.x2006.main.*; /** * High level representation of a SpreadsheetML worksheet. @@ -4051,4 +4014,69 @@ public class XSSFSheet extends POIXMLDocumentPart implements Sheet { } return col.getOutlineLevel(); } + + /** + * Add ignored errors (usually to suppress them in the UI of a consuming + * application). + * + * @param cell Cell. + * @param ignoredErrorTypes Types of error to ignore there. + */ + public void addIgnoredErrors(CellReference cell, IgnoredErrorType... ignoredErrorTypes) { + addIgnoredErrors(cell.formatAsString(), ignoredErrorTypes); + } + + /** + * Ignore errors across a range of cells. + * + * @param region Range of cells. + * @param ignoredErrorTypes Types of error to ignore there. + */ + public void addIgnoredErrors(CellRangeAddress region, IgnoredErrorType... ignoredErrorTypes) { + region.validate(SpreadsheetVersion.EXCEL2007); + addIgnoredErrors(region.formatAsString(), ignoredErrorTypes); + } + + /** + * Returns the errors currently being ignored and the ranges + * where they are ignored. + * + * @return Map of error type to the range(s) where they are ignored. + */ + public Map> getIgnoredErrors() { + Map> result = new LinkedHashMap>(); + if (worksheet.isSetIgnoredErrors()) { + for (CTIgnoredError err : worksheet.getIgnoredErrors().getIgnoredErrorList()) { + for (IgnoredErrorType errType : getErrorTypes(err)) { + if (!result.containsKey(errType)) { + result.put(errType, new LinkedHashSet()); + } + for (Object ref : err.getSqref()) { + result.get(errType).add(CellRangeAddress.valueOf(ref.toString())); + } + } + } + } + return result; + } + + private void addIgnoredErrors(String ref, IgnoredErrorType... ignoredErrorTypes) { + CTIgnoredErrors ctIgnoredErrors = worksheet.isSetIgnoredErrors() ? worksheet.getIgnoredErrors() : worksheet.addNewIgnoredErrors(); + CTIgnoredError ctIgnoredError = ctIgnoredErrors.addNewIgnoredError(); + ctIgnoredError.setSqref(Arrays.asList(ref)); + for (IgnoredErrorType errType : ignoredErrorTypes) { + errType.set(ctIgnoredError); + } + } + + private Set getErrorTypes(CTIgnoredError err) { + Set result = new LinkedHashSet(); + for (IgnoredErrorType errType : IgnoredErrorType.values()) { + if (errType.isSet(err)) { + result.add(errType); + } + } + return result; + } + } diff --git a/src/ooxml/testcases/org/apache/poi/xssf/usermodel/TestXSSFSheet.java b/src/ooxml/testcases/org/apache/poi/xssf/usermodel/TestXSSFSheet.java index 3f67825bb7..2066d2d4a9 100644 --- a/src/ooxml/testcases/org/apache/poi/xssf/usermodel/TestXSSFSheet.java +++ b/src/ooxml/testcases/org/apache/poi/xssf/usermodel/TestXSSFSheet.java @@ -33,6 +33,7 @@ import java.util.Calendar; import java.util.Date; import java.util.HashSet; import java.util.List; +import java.util.Map; import java.util.Set; import org.apache.poi.POIXMLException; @@ -68,6 +69,7 @@ import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTCell; import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTCol; import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTCols; import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTComments; +import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTIgnoredError; import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTRow; import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTSheetData; import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTSheetProtection; @@ -1828,4 +1830,75 @@ public final class TestXSSFSheet extends BaseTestSheet { public void testCopyMultipleRows() throws IOException { testCopyMultipleRows("XSSFSheet.copyRows.xlsx"); } + + @Test + public void testIgnoredErrors() throws IOException { + XSSFWorkbook workbook = new XSSFWorkbook(); + XSSFSheet sheet = workbook.createSheet(); + CellRangeAddress region = CellRangeAddress.valueOf("B2:D4"); + sheet.addIgnoredErrors(region, IgnoredErrorType.NUMBER_STORED_AS_TEXT); + final CTIgnoredError ignoredError = sheet.getCTWorksheet().getIgnoredErrors().getIgnoredErrorArray(0); + assertEquals(1, ignoredError.getSqref().size()); + assertEquals("B2:D4", ignoredError.getSqref().get(0)); + assertTrue(ignoredError.getNumberStoredAsText()); + + Map> ignoredErrors = sheet.getIgnoredErrors(); + assertEquals(1, ignoredErrors.size()); + assertEquals(1, ignoredErrors.get(IgnoredErrorType.NUMBER_STORED_AS_TEXT).size()); + assertEquals("B2:D4", ignoredErrors.get(IgnoredErrorType.NUMBER_STORED_AS_TEXT).iterator().next().formatAsString()); + + workbook.close(); + } + + @Test + public void testIgnoredErrorsMultipleTypes() throws IOException { + XSSFWorkbook workbook = new XSSFWorkbook(); + XSSFSheet sheet = workbook.createSheet(); + CellRangeAddress region = CellRangeAddress.valueOf("B2:D4"); + sheet.addIgnoredErrors(region, IgnoredErrorType.FORMULA, IgnoredErrorType.EVALUATION_ERROR); + final CTIgnoredError ignoredError = sheet.getCTWorksheet().getIgnoredErrors().getIgnoredErrorArray(0); + assertEquals(1, ignoredError.getSqref().size()); + assertEquals("B2:D4", ignoredError.getSqref().get(0)); + assertFalse(ignoredError.getNumberStoredAsText()); + assertTrue(ignoredError.getFormula()); + assertTrue(ignoredError.getEvalError()); + + Map> ignoredErrors = sheet.getIgnoredErrors(); + assertEquals(2, ignoredErrors.size()); + assertEquals(1, ignoredErrors.get(IgnoredErrorType.FORMULA).size()); + assertEquals("B2:D4", ignoredErrors.get(IgnoredErrorType.FORMULA).iterator().next().formatAsString()); + assertEquals(1, ignoredErrors.get(IgnoredErrorType.EVALUATION_ERROR).size()); + assertEquals("B2:D4", ignoredErrors.get(IgnoredErrorType.EVALUATION_ERROR).iterator().next().formatAsString()); + workbook.close(); + } + + @Test + public void testIgnoredErrorsMultipleCalls() throws IOException { + XSSFWorkbook workbook = new XSSFWorkbook(); + XSSFSheet sheet = workbook.createSheet(); + CellRangeAddress region = CellRangeAddress.valueOf("B2:D4"); + // Two calls means two elements, no clever collapsing just yet. + sheet.addIgnoredErrors(region, IgnoredErrorType.EVALUATION_ERROR); + sheet.addIgnoredErrors(region, IgnoredErrorType.FORMULA); + + CTIgnoredError ignoredError = sheet.getCTWorksheet().getIgnoredErrors().getIgnoredErrorArray(0); + assertEquals(1, ignoredError.getSqref().size()); + assertEquals("B2:D4", ignoredError.getSqref().get(0)); + assertFalse(ignoredError.getFormula()); + assertTrue(ignoredError.getEvalError()); + + ignoredError = sheet.getCTWorksheet().getIgnoredErrors().getIgnoredErrorArray(1); + assertEquals(1, ignoredError.getSqref().size()); + assertEquals("B2:D4", ignoredError.getSqref().get(0)); + assertTrue(ignoredError.getFormula()); + assertFalse(ignoredError.getEvalError()); + + Map> ignoredErrors = sheet.getIgnoredErrors(); + assertEquals(2, ignoredErrors.size()); + assertEquals(1, ignoredErrors.get(IgnoredErrorType.FORMULA).size()); + assertEquals("B2:D4", ignoredErrors.get(IgnoredErrorType.FORMULA).iterator().next().formatAsString()); + assertEquals(1, ignoredErrors.get(IgnoredErrorType.EVALUATION_ERROR).size()); + assertEquals("B2:D4", ignoredErrors.get(IgnoredErrorType.EVALUATION_ERROR).iterator().next().formatAsString()); + workbook.close(); + } } \ No newline at end of file