diff options
5 files changed, 119 insertions, 17 deletions
diff --git a/src/documentation/content/xdocs/status.xml b/src/documentation/content/xdocs/status.xml index 79da11ad82..b0ae08f9b9 100644 --- a/src/documentation/content/xdocs/status.xml +++ b/src/documentation/content/xdocs/status.xml @@ -34,6 +34,7 @@ <changes> <release version="3.7-SNAPSHOT" date="2010-??-??"> + <action dev="POI-DEVELOPERS" type="add">48617 - Optionally allow the overriding of the Locale used by DataFormatter to control how the default number and date formats should look</action> <action dev="POI-DEVELOPERS" type="add">New event based xssf text extractor (XSSFEventBasedExcelExtractor)</action> <action dev="POI-DEVELOPERS" type="add">ExtractorFactory can now be told to prefer Event Based extractors (current Excel only) on a per-thread or overall basis</action> <action dev="POI-DEVELOPERS" type="fix">48544 - avoid failures in XLSX2CSV when shared string table is missing</action> diff --git a/src/java/org/apache/poi/hssf/eventusermodel/FormatTrackingHSSFListener.java b/src/java/org/apache/poi/hssf/eventusermodel/FormatTrackingHSSFListener.java index 5e21bdf58e..60c11d3521 100644 --- a/src/java/org/apache/poi/hssf/eventusermodel/FormatTrackingHSSFListener.java +++ b/src/java/org/apache/poi/hssf/eventusermodel/FormatTrackingHSSFListener.java @@ -16,9 +16,11 @@ ==================================================================== */ package org.apache.poi.hssf.eventusermodel; +import java.text.NumberFormat; import java.util.ArrayList; import java.util.Hashtable; import java.util.List; +import java.util.Locale; import java.util.Map; import org.apache.poi.hssf.record.CellValueRecordInterface; @@ -37,12 +39,28 @@ import org.apache.poi.hssf.usermodel.HSSFDataFormatter; */ public class FormatTrackingHSSFListener implements HSSFListener { private final HSSFListener _childListener; - private HSSFDataFormatter _formatter = new HSSFDataFormatter(); + private final HSSFDataFormatter _formatter; + private final NumberFormat _defaultFormat; private final Map<Integer, FormatRecord> _customFormatRecords = new Hashtable<Integer, FormatRecord>(); private final List<ExtendedFormatRecord> _xfRecords = new ArrayList<ExtendedFormatRecord>(); + /** + * Creates a format tracking wrapper around the given listener, using + * the {@link Locale#getDefault() default locale} for the formats. + */ public FormatTrackingHSSFListener(HSSFListener childListener) { + this(childListener, Locale.getDefault()); + } + + /** + * Creates a format tracking wrapper around the given listener, using + * the given locale for the formats. + */ + public FormatTrackingHSSFListener( + HSSFListener childListener, Locale locale) { _childListener = childListener; + _formatter = new HSSFDataFormatter(locale); + _defaultFormat = NumberFormat.getInstance(locale); } protected int getNumberOfCustomFormats() { @@ -104,7 +122,7 @@ public class FormatTrackingHSSFListener implements HSSFListener { String formatString = getFormatString(cell); if (formatString == null) { - return Double.toString(value); + return _defaultFormat.format(value); } // Format, using the nice new // HSSFDataFormatter to do the work for us diff --git a/src/java/org/apache/poi/hssf/usermodel/HSSFDataFormatter.java b/src/java/org/apache/poi/hssf/usermodel/HSSFDataFormatter.java index 6396492d8e..0024639ff5 100644 --- a/src/java/org/apache/poi/hssf/usermodel/HSSFDataFormatter.java +++ b/src/java/org/apache/poi/hssf/usermodel/HSSFDataFormatter.java @@ -20,6 +20,7 @@ package org.apache.poi.hssf.usermodel; import java.text.DecimalFormat; import java.text.Format; import java.text.SimpleDateFormat; +import java.util.Locale; import org.apache.poi.ss.usermodel.DataFormatter; @@ -66,4 +67,18 @@ import org.apache.poi.ss.usermodel.DataFormatter; */ public final class HSSFDataFormatter extends DataFormatter { + /** + * Creates a formatter using the given locale. + */ + public HSSFDataFormatter(Locale locale) { + super(locale); + } + + /** + * Creates a formatter using the {@link Locale#getDefault() default locale}. + */ + public HSSFDataFormatter() { + this(Locale.getDefault()); + } + } diff --git a/src/java/org/apache/poi/ss/usermodel/DataFormatter.java b/src/java/org/apache/poi/ss/usermodel/DataFormatter.java index bb7ef000e4..053e37cb50 100644 --- a/src/java/org/apache/poi/ss/usermodel/DataFormatter.java +++ b/src/java/org/apache/poi/ss/usermodel/DataFormatter.java @@ -77,11 +77,21 @@ public class DataFormatter { /** A regex to find patterns like [$$-1009] and [$?-452]. */ private static final Pattern specialPatternGroup = Pattern.compile("(\\[\\$[^-\\]]*-[0-9A-Z]+\\])"); + /** + * The decimal symbols of the locale used for formatting values. + */ + private final DecimalFormatSymbols decimalSymbols; + + /** + * The date symbols of the locale used for formatting values. + */ + private final DateFormatSymbols dateSymbols; + /** <em>General</em> format for whole numbers. */ - private static final Format generalWholeNumFormat = new DecimalFormat("#"); + private final Format generalWholeNumFormat; /** <em>General</em> format for decimal numbers. */ - private static final Format generalDecimalNumFormat = new DecimalFormat("#.##########"); + private final Format generalDecimalNumFormat; /** A default format to use when a number pattern cannot be parsed. */ private Format defaultNumFormat; @@ -90,13 +100,25 @@ public class DataFormatter { * A map to cache formats. * Map<String,Format> formats */ - private final Map formats; + private final Map<String,Format> formats; /** - * Constructor + * Creates a formatter using the {@link Locale#getDefault() default locale}. */ public DataFormatter() { - formats = new HashMap(); + this(Locale.getDefault()); + } + + /** + * Creates a formatter using the given locale. + */ + public DataFormatter(Locale locale) { + dateSymbols = new DateFormatSymbols(locale); + decimalSymbols = new DecimalFormatSymbols(locale); + generalWholeNumFormat = new DecimalFormat("#", decimalSymbols); + generalDecimalNumFormat = new DecimalFormat("#.##########", decimalSymbols); + + formats = new HashMap<String,Format>(); // init built-in formats @@ -143,7 +165,7 @@ public class DataFormatter { } private Format getFormat(double cellValue, int formatIndex, String formatStr) { - Format format = (Format)formats.get(formatStr); + Format format = formats.get(formatStr); if (format != null) { return format; } @@ -242,7 +264,7 @@ public class DataFormatter { StringBuffer sb = new StringBuffer(); char[] chars = formatStr.toCharArray(); boolean mIsMonth = true; - List ms = new ArrayList(); + List<Integer> ms = new ArrayList<Integer>(); for(int j=0; j<chars.length; j++) { char c = chars[j]; if (c == 'h' || c == 'H') { @@ -267,7 +289,7 @@ public class DataFormatter { sb.append('s'); // if 'M' precedes 's' it should be minutes ('m') for (int i = 0; i < ms.size(); i++) { - int index = ((Integer)ms.get(i)).intValue(); + int index = ms.get(i).intValue(); if (sb.charAt(index) == 'M') { sb.replace(index, index+1, "m"); } @@ -295,7 +317,7 @@ public class DataFormatter { formatStr = sb.toString(); try { - return new SimpleDateFormat(formatStr); + return new SimpleDateFormat(formatStr, dateSymbols); } catch(IllegalArgumentException iae) { // the pattern could not be parsed correctly, @@ -335,7 +357,7 @@ public class DataFormatter { } try { - return new DecimalFormat(sb.toString()); + return new DecimalFormat(sb.toString(), decimalSymbols); } catch(IllegalArgumentException iae) { // the pattern could not be parsed correctly, @@ -520,9 +542,9 @@ public class DataFormatter { * @see java.text.Format#format */ public void setDefaultNumberFormat(Format format) { - Iterator itr = formats.entrySet().iterator(); + Iterator<Map.Entry<String,Format>> itr = formats.entrySet().iterator(); while(itr.hasNext()) { - Map.Entry entry = (Map.Entry)itr.next(); + Map.Entry<String,Format> entry = itr.next(); if (entry.getValue() == generalDecimalNumFormat || entry.getValue() == generalWholeNumFormat) { entry.setValue(format); @@ -562,7 +584,8 @@ public class DataFormatter { * * @author James May */ - private static final class SSNFormat extends Format { + @SuppressWarnings("serial") + private static final class SSNFormat extends Format { public static final Format instance = new SSNFormat(); private static final DecimalFormat df = createIntegerOnlyFormat("000000000"); private SSNFormat() { @@ -593,7 +616,8 @@ public class DataFormatter { * built-in formatting for Zip + 4. * @author James May */ - private static final class ZipPlusFourFormat extends Format { + @SuppressWarnings("serial") + private static final class ZipPlusFourFormat extends Format { public static final Format instance = new ZipPlusFourFormat(); private static final DecimalFormat df = createIntegerOnlyFormat("000000000"); private ZipPlusFourFormat() { @@ -623,7 +647,8 @@ public class DataFormatter { * built-in phone number formatting. * @author James May */ - private static final class PhoneFormat extends Format { + @SuppressWarnings("serial") + private static final class PhoneFormat extends Format { public static final Format instance = new PhoneFormat(); private static final DecimalFormat df = createIntegerOnlyFormat("##########"); private PhoneFormat() { diff --git a/src/testcases/org/apache/poi/ss/usermodel/TestDataFormatter.java b/src/testcases/org/apache/poi/ss/usermodel/TestDataFormatter.java new file mode 100644 index 0000000000..73c15e8c44 --- /dev/null +++ b/src/testcases/org/apache/poi/ss/usermodel/TestDataFormatter.java @@ -0,0 +1,43 @@ +/* ==================================================================== + 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.ss.usermodel; + +import java.util.Locale; + +import junit.framework.TestCase; + +/** + * Tests of {@link DataFormatter} + * + */ +public class TestDataFormatter extends TestCase { + /** + * Test that we use the specified locale when deciding + * how to format normal numbers + */ + public void testLocale() { + DataFormatter dfUS = new DataFormatter(Locale.US); + DataFormatter dfFR = new DataFormatter(Locale.FRENCH); + + assertEquals("1234", dfUS.formatRawCellContents(1234, -1, "@")); + assertEquals("1234", dfFR.formatRawCellContents(1234, -1, "@")); + + assertEquals("12.34", dfUS.formatRawCellContents(12.34, -1, "@")); + assertEquals("12,34", dfFR.formatRawCellContents(12.34, -1, "@")); + } +} |