Add patch from Jukka from bug #48617 + test - Optionally allow the overriding of the Locale used by DataFormatter to control how the default number and date formats should look
git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@903303 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
parent
a2e6cafca9
commit
81755dc8d2
@ -34,6 +34,7 @@
|
|||||||
|
|
||||||
<changes>
|
<changes>
|
||||||
<release version="3.7-SNAPSHOT" date="2010-??-??">
|
<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">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="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>
|
<action dev="POI-DEVELOPERS" type="fix">48544 - avoid failures in XLSX2CSV when shared string table is missing</action>
|
||||||
|
@ -16,9 +16,11 @@
|
|||||||
==================================================================== */
|
==================================================================== */
|
||||||
package org.apache.poi.hssf.eventusermodel;
|
package org.apache.poi.hssf.eventusermodel;
|
||||||
|
|
||||||
|
import java.text.NumberFormat;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Hashtable;
|
import java.util.Hashtable;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Locale;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
import org.apache.poi.hssf.record.CellValueRecordInterface;
|
import org.apache.poi.hssf.record.CellValueRecordInterface;
|
||||||
@ -37,12 +39,28 @@ import org.apache.poi.hssf.usermodel.HSSFDataFormatter;
|
|||||||
*/
|
*/
|
||||||
public class FormatTrackingHSSFListener implements HSSFListener {
|
public class FormatTrackingHSSFListener implements HSSFListener {
|
||||||
private final HSSFListener _childListener;
|
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 Map<Integer, FormatRecord> _customFormatRecords = new Hashtable<Integer, FormatRecord>();
|
||||||
private final List<ExtendedFormatRecord> _xfRecords = new ArrayList<ExtendedFormatRecord>();
|
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) {
|
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;
|
_childListener = childListener;
|
||||||
|
_formatter = new HSSFDataFormatter(locale);
|
||||||
|
_defaultFormat = NumberFormat.getInstance(locale);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected int getNumberOfCustomFormats() {
|
protected int getNumberOfCustomFormats() {
|
||||||
@ -104,7 +122,7 @@ public class FormatTrackingHSSFListener implements HSSFListener {
|
|||||||
String formatString = getFormatString(cell);
|
String formatString = getFormatString(cell);
|
||||||
|
|
||||||
if (formatString == null) {
|
if (formatString == null) {
|
||||||
return Double.toString(value);
|
return _defaultFormat.format(value);
|
||||||
}
|
}
|
||||||
// Format, using the nice new
|
// Format, using the nice new
|
||||||
// HSSFDataFormatter to do the work for us
|
// HSSFDataFormatter to do the work for us
|
||||||
|
@ -20,6 +20,7 @@ package org.apache.poi.hssf.usermodel;
|
|||||||
import java.text.DecimalFormat;
|
import java.text.DecimalFormat;
|
||||||
import java.text.Format;
|
import java.text.Format;
|
||||||
import java.text.SimpleDateFormat;
|
import java.text.SimpleDateFormat;
|
||||||
|
import java.util.Locale;
|
||||||
|
|
||||||
import org.apache.poi.ss.usermodel.DataFormatter;
|
import org.apache.poi.ss.usermodel.DataFormatter;
|
||||||
|
|
||||||
@ -66,4 +67,18 @@ import org.apache.poi.ss.usermodel.DataFormatter;
|
|||||||
*/
|
*/
|
||||||
public final class HSSFDataFormatter extends 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());
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -77,11 +77,21 @@ public class DataFormatter {
|
|||||||
/** A regex to find patterns like [$$-1009] and [$?-452]. */
|
/** A regex to find patterns like [$$-1009] and [$?-452]. */
|
||||||
private static final Pattern specialPatternGroup = Pattern.compile("(\\[\\$[^-\\]]*-[0-9A-Z]+\\])");
|
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. */
|
/** <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. */
|
/** <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. */
|
/** A default format to use when a number pattern cannot be parsed. */
|
||||||
private Format defaultNumFormat;
|
private Format defaultNumFormat;
|
||||||
@ -90,13 +100,25 @@ public class DataFormatter {
|
|||||||
* A map to cache formats.
|
* A map to cache formats.
|
||||||
* Map<String,Format> 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() {
|
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
|
// init built-in formats
|
||||||
|
|
||||||
@ -143,7 +165,7 @@ public class DataFormatter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private Format getFormat(double cellValue, int formatIndex, String formatStr) {
|
private Format getFormat(double cellValue, int formatIndex, String formatStr) {
|
||||||
Format format = (Format)formats.get(formatStr);
|
Format format = formats.get(formatStr);
|
||||||
if (format != null) {
|
if (format != null) {
|
||||||
return format;
|
return format;
|
||||||
}
|
}
|
||||||
@ -242,7 +264,7 @@ public class DataFormatter {
|
|||||||
StringBuffer sb = new StringBuffer();
|
StringBuffer sb = new StringBuffer();
|
||||||
char[] chars = formatStr.toCharArray();
|
char[] chars = formatStr.toCharArray();
|
||||||
boolean mIsMonth = true;
|
boolean mIsMonth = true;
|
||||||
List ms = new ArrayList();
|
List<Integer> ms = new ArrayList<Integer>();
|
||||||
for(int j=0; j<chars.length; j++) {
|
for(int j=0; j<chars.length; j++) {
|
||||||
char c = chars[j];
|
char c = chars[j];
|
||||||
if (c == 'h' || c == 'H') {
|
if (c == 'h' || c == 'H') {
|
||||||
@ -267,7 +289,7 @@ public class DataFormatter {
|
|||||||
sb.append('s');
|
sb.append('s');
|
||||||
// if 'M' precedes 's' it should be minutes ('m')
|
// if 'M' precedes 's' it should be minutes ('m')
|
||||||
for (int i = 0; i < ms.size(); i++) {
|
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') {
|
if (sb.charAt(index) == 'M') {
|
||||||
sb.replace(index, index+1, "m");
|
sb.replace(index, index+1, "m");
|
||||||
}
|
}
|
||||||
@ -295,7 +317,7 @@ public class DataFormatter {
|
|||||||
formatStr = sb.toString();
|
formatStr = sb.toString();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
return new SimpleDateFormat(formatStr);
|
return new SimpleDateFormat(formatStr, dateSymbols);
|
||||||
} catch(IllegalArgumentException iae) {
|
} catch(IllegalArgumentException iae) {
|
||||||
|
|
||||||
// the pattern could not be parsed correctly,
|
// the pattern could not be parsed correctly,
|
||||||
@ -335,7 +357,7 @@ public class DataFormatter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
return new DecimalFormat(sb.toString());
|
return new DecimalFormat(sb.toString(), decimalSymbols);
|
||||||
} catch(IllegalArgumentException iae) {
|
} catch(IllegalArgumentException iae) {
|
||||||
|
|
||||||
// the pattern could not be parsed correctly,
|
// the pattern could not be parsed correctly,
|
||||||
@ -520,9 +542,9 @@ public class DataFormatter {
|
|||||||
* @see java.text.Format#format
|
* @see java.text.Format#format
|
||||||
*/
|
*/
|
||||||
public void setDefaultNumberFormat(Format format) {
|
public void setDefaultNumberFormat(Format format) {
|
||||||
Iterator itr = formats.entrySet().iterator();
|
Iterator<Map.Entry<String,Format>> itr = formats.entrySet().iterator();
|
||||||
while(itr.hasNext()) {
|
while(itr.hasNext()) {
|
||||||
Map.Entry entry = (Map.Entry)itr.next();
|
Map.Entry<String,Format> entry = itr.next();
|
||||||
if (entry.getValue() == generalDecimalNumFormat
|
if (entry.getValue() == generalDecimalNumFormat
|
||||||
|| entry.getValue() == generalWholeNumFormat) {
|
|| entry.getValue() == generalWholeNumFormat) {
|
||||||
entry.setValue(format);
|
entry.setValue(format);
|
||||||
@ -562,6 +584,7 @@ public class DataFormatter {
|
|||||||
*
|
*
|
||||||
* @author James May
|
* @author James May
|
||||||
*/
|
*/
|
||||||
|
@SuppressWarnings("serial")
|
||||||
private static final class SSNFormat extends Format {
|
private static final class SSNFormat extends Format {
|
||||||
public static final Format instance = new SSNFormat();
|
public static final Format instance = new SSNFormat();
|
||||||
private static final DecimalFormat df = createIntegerOnlyFormat("000000000");
|
private static final DecimalFormat df = createIntegerOnlyFormat("000000000");
|
||||||
@ -593,6 +616,7 @@ public class DataFormatter {
|
|||||||
* built-in formatting for Zip + 4.
|
* built-in formatting for Zip + 4.
|
||||||
* @author James May
|
* @author James May
|
||||||
*/
|
*/
|
||||||
|
@SuppressWarnings("serial")
|
||||||
private static final class ZipPlusFourFormat extends Format {
|
private static final class ZipPlusFourFormat extends Format {
|
||||||
public static final Format instance = new ZipPlusFourFormat();
|
public static final Format instance = new ZipPlusFourFormat();
|
||||||
private static final DecimalFormat df = createIntegerOnlyFormat("000000000");
|
private static final DecimalFormat df = createIntegerOnlyFormat("000000000");
|
||||||
@ -623,6 +647,7 @@ public class DataFormatter {
|
|||||||
* built-in phone number formatting.
|
* built-in phone number formatting.
|
||||||
* @author James May
|
* @author James May
|
||||||
*/
|
*/
|
||||||
|
@SuppressWarnings("serial")
|
||||||
private static final class PhoneFormat extends Format {
|
private static final class PhoneFormat extends Format {
|
||||||
public static final Format instance = new PhoneFormat();
|
public static final Format instance = new PhoneFormat();
|
||||||
private static final DecimalFormat df = createIntegerOnlyFormat("##########");
|
private static final DecimalFormat df = createIntegerOnlyFormat("##########");
|
||||||
|
@ -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, "@"));
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user