From 869277010f15caee118ec43b9d1180efde89d62c Mon Sep 17 00:00:00 2001 From: Luca Martini Date: Thu, 1 Jun 2017 16:34:24 +0200 Subject: [PATCH 1/2] Implemented custom formats with trailing commas. Added two unit tests. (cherry picked from commit 4679c75) --- .../poi/ss/usermodel/DataFormatter.java | 85 +++++++++++++------ .../poi/ss/usermodel/TestDataFormatter.java | 53 +++++++++--- 2 files changed, 99 insertions(+), 39 deletions(-) diff --git a/src/java/org/apache/poi/ss/usermodel/DataFormatter.java b/src/java/org/apache/poi/ss/usermodel/DataFormatter.java index f07225432cf..eed59310188 100644 --- a/src/java/org/apache/poi/ss/usermodel/DataFormatter.java +++ b/src/java/org/apache/poi/ss/usermodel/DataFormatter.java @@ -20,27 +20,6 @@ Licensed to the Apache Software Foundation (ASF) under one or more ==================================================================== */ package org.apache.poi.ss.usermodel; -import java.math.BigDecimal; -import java.math.RoundingMode; -import java.text.DateFormat; -import java.text.DateFormatSymbols; -import java.text.DecimalFormat; -import java.text.DecimalFormatSymbols; -import java.text.FieldPosition; -import java.text.Format; -import java.text.ParsePosition; -import java.text.SimpleDateFormat; -import java.util.ArrayList; -import java.util.Date; -import java.util.HashMap; -import java.util.List; -import java.util.Locale; -import java.util.Map; -import java.util.Observable; -import java.util.Observer; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - import org.apache.poi.ss.format.CellFormat; import org.apache.poi.ss.format.CellFormatResult; import org.apache.poi.ss.formula.ConditionalFormattingEvaluator; @@ -50,6 +29,13 @@ Licensed to the Apache Software Foundation (ASF) under one or more import org.apache.poi.util.POILogFactory; import org.apache.poi.util.POILogger; +import java.math.BigDecimal; +import java.math.RoundingMode; +import java.text.*; +import java.util.*; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + /** * DataFormatter contains methods for formatting the value stored in an @@ -691,6 +677,57 @@ private String cleanFormatForNumber(String formatStr) { return sb.toString(); } + private static class InternalDecimalFormatWithScale extends Format { + + private static final Pattern endsWithCommas = Pattern.compile("(,+)$"); + private BigDecimal divider; + private static final BigDecimal ONE_THOUSAND = new BigDecimal(1000); + private final DecimalFormat df; + private static final String trimTrailingCommas(String s) { + return s.replaceAll(",+$", ""); + } + + public InternalDecimalFormatWithScale(String pattern, DecimalFormatSymbols symbols) { + df = new DecimalFormat(trimTrailingCommas(pattern), symbols); + setExcelStyleRoundingMode(df); + Matcher endsWithCommasMatcher = endsWithCommas.matcher(pattern); + if (endsWithCommasMatcher.find()) { + String commas = (endsWithCommasMatcher.group(1)); + BigDecimal temp = BigDecimal.ONE; + for (int i = 0; i < commas.length(); ++i) { + temp = temp.multiply(ONE_THOUSAND); + } + divider = temp; + } else { + divider = null; + } + } + + private Object scaleInput(Object obj) { + if (divider != null) { + if (obj instanceof BigDecimal) { + obj = ((BigDecimal) obj).divide(divider, RoundingMode.HALF_UP); + } else if (obj instanceof Double) { + obj = (Double) obj / divider.doubleValue(); + } else { + throw new UnsupportedOperationException(); + } + } + return obj; + } + + @Override + public StringBuffer format(Object obj, StringBuffer toAppendTo, FieldPosition pos) { + obj = scaleInput(obj); + return df.format(obj, toAppendTo, pos); + } + + @Override + public Object parseObject(String source, ParsePosition pos) { + throw new UnsupportedOperationException(); + } + } + private Format createNumberFormat(String formatStr, double cellValue) { String format = cleanFormatForNumber(formatStr); DecimalFormatSymbols symbols = decimalSymbols; @@ -714,11 +751,8 @@ private Format createNumberFormat(String formatStr, double cellValue) { } try { - DecimalFormat df = new DecimalFormat(format, symbols); - setExcelStyleRoundingMode(df); - return df; + return new InternalDecimalFormatWithScale(format, symbols); } catch(IllegalArgumentException iae) { - // the pattern could not be parsed correctly, // so fall back to the default number format return getDefaultFormat(cellValue); @@ -1021,7 +1055,6 @@ private static DecimalFormat createIntegerOnlyFormat(String fmt) { * Decimal Format given. */ public static void setExcelStyleRoundingMode(DecimalFormat format) { - setExcelStyleRoundingMode(format, RoundingMode.HALF_UP); } /** diff --git a/src/testcases/org/apache/poi/ss/usermodel/TestDataFormatter.java b/src/testcases/org/apache/poi/ss/usermodel/TestDataFormatter.java index b4f3b7dde40..f8313858191 100644 --- a/src/testcases/org/apache/poi/ss/usermodel/TestDataFormatter.java +++ b/src/testcases/org/apache/poi/ss/usermodel/TestDataFormatter.java @@ -21,17 +21,6 @@ Licensed to the Apache Software Foundation (ASF) under one or more package org.apache.poi.ss.usermodel; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; - -import java.io.IOException; -import java.text.DateFormat; -import java.util.Calendar; -import java.util.Date; -import java.util.Locale; - import org.apache.poi.hssf.HSSFTestDataSamples; import org.apache.poi.hssf.usermodel.HSSFWorkbook; import org.apache.poi.hssf.usermodel.TestHSSFDataFormatter; @@ -45,6 +34,14 @@ Licensed to the Apache Software Foundation (ASF) under one or more import org.junit.Ignore; import org.junit.Test; +import java.io.IOException; +import java.text.DateFormat; +import java.util.Calendar; +import java.util.Date; +import java.util.Locale; + +import static org.junit.Assert.*; + /** * Tests of {@link DataFormatter} * @@ -198,7 +195,7 @@ public void testColoursAndBrackets() { ); } } - + @Test public void testConditionalRanges() { DataFormatter dfUS = new DataFormatter(Locale.US); @@ -826,7 +823,37 @@ public void testFormulaEvaluation() throws IOException { wb.close(); } - + + @Test + public void testFormatWithTrailingDotsUS() { + DataFormatter dfUS = new DataFormatter(Locale.US); + assertEquals("1,000,000", dfUS.formatRawCellContents(1000000, -1, "#,##0")); + assertEquals("1,000", dfUS.formatRawCellContents(1000000, -1, "#,##0,")); + assertEquals("1", dfUS.formatRawCellContents(1000000, -1, "#,##0,,")); + assertEquals("1,000,000.0", dfUS.formatRawCellContents(1000000, -1, "#,##0.0")); + assertEquals("1,000.0", dfUS.formatRawCellContents(1000000, -1, "#,##0.0,")); + assertEquals("1.0", dfUS.formatRawCellContents(1000000, -1, "#,##0.0,,")); + assertEquals("1,000,000.00", dfUS.formatRawCellContents(1000000, -1, "#,##0.00")); + assertEquals("1,000.00", dfUS.formatRawCellContents(1000000, -1, "#,##0.00,")); + assertEquals("1.00", dfUS.formatRawCellContents(1000000, -1, "#,##0.00,,")); + assertEquals("1,000,000", dfUS.formatRawCellContents(1e24, -1, "#,##0,,,,,,")); + } + + @Test + public void testFormatWithTrailingDotsOtherLocale() throws Exception { + DataFormatter dfIT = new DataFormatter(Locale.ITALY); + assertEquals("1.000.000", dfIT.formatRawCellContents(1000000, -1, "#,##0")); + assertEquals("1.000", dfIT.formatRawCellContents(1000000, -1, "#,##0,")); + assertEquals("1", dfIT.formatRawCellContents(1000000, -1, "#,##0,,")); + assertEquals("1.000.000,0", dfIT.formatRawCellContents(1000000, -1, "#,##0.0")); + assertEquals("1.000,0", dfIT.formatRawCellContents(1000000, -1, "#,##0.0,")); + assertEquals("1,0", dfIT.formatRawCellContents(1000000, -1, "#,##0.0,,")); + assertEquals("1.000.000,00", dfIT.formatRawCellContents(1000000, -1, "#,##0.00")); + assertEquals("1.000,00", dfIT.formatRawCellContents(1000000, -1, "#,##0.00,")); + assertEquals("1,00", dfIT.formatRawCellContents(1000000, -1, "#,##0.00,,")); + assertEquals("1.000.000", dfIT.formatRawCellContents(1e24, -1, "#,##0,,,,,,")); + } + /** * bug 60031: DataFormatter parses months incorrectly when put at the end of date segment */ From a7ecab98652bdcfffc8771701f7e6cac677bdd1f Mon Sep 17 00:00:00 2001 From: Luca Martini Date: Thu, 1 Jun 2017 17:15:08 +0200 Subject: [PATCH 2/2] Implemented custom formats with trailing commas. Restored method deleted by error --- src/java/org/apache/poi/ss/usermodel/DataFormatter.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/java/org/apache/poi/ss/usermodel/DataFormatter.java b/src/java/org/apache/poi/ss/usermodel/DataFormatter.java index eed59310188..0c6a436d673 100644 --- a/src/java/org/apache/poi/ss/usermodel/DataFormatter.java +++ b/src/java/org/apache/poi/ss/usermodel/DataFormatter.java @@ -1055,6 +1055,7 @@ private static DecimalFormat createIntegerOnlyFormat(String fmt) { * Decimal Format given. */ public static void setExcelStyleRoundingMode(DecimalFormat format) { + setExcelStyleRoundingMode(format, RoundingMode.HALF_UP); } /**