git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@1800713 13f79535-47bb-0310-9956-ffa450edef68tags/REL_3_17_FINAL
@@ -138,6 +138,16 @@ public class CellDateFormatter extends CellFormatter { | |||
* @param format The format. | |||
*/ | |||
public CellDateFormatter(String format) { | |||
this(LocaleUtil.getUserLocale(), format); | |||
} | |||
/** | |||
* Creates a new date formatter with the given specification. | |||
* | |||
* @param locale The locale. | |||
* @param format The format. | |||
*/ | |||
public CellDateFormatter(Locale locale, String format) { | |||
super(format); | |||
DatePartHandler partHandler = new DatePartHandler(); | |||
StringBuffer descBuf = CellFormatPart.parseFormat(format, | |||
@@ -146,7 +156,7 @@ public class CellDateFormatter extends CellFormatter { | |||
// tweak the format pattern to pass tests on JDK 1.7, | |||
// See https://issues.apache.org/bugzilla/show_bug.cgi?id=53369 | |||
String ptrn = descBuf.toString().replaceAll("((y)(?!y))(?<!yy)", "yy"); | |||
dateFmt = new SimpleDateFormat(ptrn, LocaleUtil.getUserLocale()); | |||
dateFmt = new SimpleDateFormat(ptrn, locale); | |||
dateFmt.setTimeZone(LocaleUtil.getUserTimeZone()); | |||
} | |||
@@ -182,7 +192,7 @@ public class CellDateFormatter extends CellFormatter { | |||
Formatter formatter = new Formatter(toAppendTo, Locale.ROOT); | |||
try { | |||
long msecs = dateObj.getTime() % 1000; | |||
formatter.format(LocaleUtil.getUserLocale(), sFmt, msecs / 1000.0); | |||
formatter.format(locale, sFmt, msecs / 1000.0); | |||
} finally { | |||
formatter.close(); | |||
} |
@@ -20,6 +20,7 @@ package org.apache.poi.ss.format; | |||
import java.util.ArrayList; | |||
import java.util.Date; | |||
import java.util.List; | |||
import java.util.Locale; | |||
import java.util.Map; | |||
import java.util.WeakHashMap; | |||
import java.util.logging.Level; | |||
@@ -35,6 +36,7 @@ import org.apache.poi.ss.usermodel.ConditionalFormattingRule; | |||
import org.apache.poi.ss.usermodel.DataFormatter; | |||
import org.apache.poi.ss.usermodel.DateUtil; | |||
import org.apache.poi.ss.util.DateFormatConverter; | |||
import org.apache.poi.util.LocaleUtil; | |||
/** | |||
* Format a value according to the standard Excel behavior. This "standard" is | |||
@@ -90,6 +92,7 @@ import org.apache.poi.ss.util.DateFormatConverter; | |||
* native character numbers, as documented at https://help.libreoffice.org/Common/Number_Format_Codes | |||
*/ | |||
public class CellFormat { | |||
private final Locale locale; | |||
private final String format; | |||
private final CellFormatPart posNumFmt; | |||
private final CellFormatPart zeroNumFmt; | |||
@@ -101,9 +104,6 @@ public class CellFormat { | |||
CellFormatPart.FORMAT_PAT.pattern() + "(;|$)", | |||
Pattern.COMMENTS | Pattern.CASE_INSENSITIVE); | |||
private static final CellFormatPart DEFAULT_TEXT_FORMAT = | |||
new CellFormatPart("@"); | |||
/* | |||
* Cells that cannot be formatted, e.g. cells that have a date or time | |||
* format and have an invalid date or time value, are displayed as 255 | |||
@@ -121,18 +121,23 @@ public class CellFormat { | |||
/** | |||
* Format a value as it would be were no format specified. This is also | |||
* used when the format specified is <tt>General</tt>. | |||
* @deprecated use {@link #getInstance(Locale, "General")} instead | |||
*/ | |||
public static final CellFormat GENERAL_FORMAT = new CellFormat("General") { | |||
@Override | |||
public CellFormatResult apply(Object value) { | |||
String text = (new CellGeneralFormatter()).format(value); | |||
return new CellFormatResult(true, text, null); | |||
} | |||
}; | |||
public static final CellFormat GENERAL_FORMAT = createGeneralFormat(LocaleUtil.getUserLocale()); | |||
private static CellFormat createGeneralFormat(final Locale locale) { | |||
return new CellFormat(locale, "General") { | |||
@Override | |||
public CellFormatResult apply(Object value) { | |||
String text = (new CellGeneralFormatter(locale)).format(value); | |||
return new CellFormatResult(true, text, null); | |||
} | |||
}; | |||
} | |||
/** Maps a format string to its parsed version for efficiencies sake. */ | |||
private static final Map<String, CellFormat> formatCache = | |||
new WeakHashMap<String, CellFormat>(); | |||
private static final Map<Locale, Map<String, CellFormat>> formatCache = | |||
new WeakHashMap<Locale, Map<String, CellFormat>>(); | |||
/** | |||
* Returns a {@link CellFormat} that applies the given format. Two calls | |||
@@ -143,13 +148,31 @@ public class CellFormat { | |||
* @return A {@link CellFormat} that applies the given format. | |||
*/ | |||
public static CellFormat getInstance(String format) { | |||
CellFormat fmt = formatCache.get(format); | |||
return getInstance(LocaleUtil.getUserLocale(), format); | |||
} | |||
/** | |||
* Returns a {@link CellFormat} that applies the given format. Two calls | |||
* with the same format may or may not return the same object. | |||
* | |||
* @param locale The locale. | |||
* @param format The format. | |||
* | |||
* @return A {@link CellFormat} that applies the given format. | |||
*/ | |||
public static synchronized CellFormat getInstance(Locale locale, String format) { | |||
Map<String, CellFormat> formatMap = formatCache.get(locale); | |||
if (formatMap == null) { | |||
formatMap = new WeakHashMap<String, CellFormat>(); | |||
formatCache.put(locale, formatMap); | |||
} | |||
CellFormat fmt = formatMap.get(format); | |||
if (fmt == null) { | |||
if (format.equals("General") || format.equals("@")) | |||
fmt = GENERAL_FORMAT; | |||
fmt = createGeneralFormat(locale); | |||
else | |||
fmt = new CellFormat(format); | |||
formatCache.put(format, fmt); | |||
fmt = new CellFormat(locale, format); | |||
formatMap.put(format, fmt); | |||
} | |||
return fmt; | |||
} | |||
@@ -159,8 +182,10 @@ public class CellFormat { | |||
* | |||
* @param format The format. | |||
*/ | |||
private CellFormat(String format) { | |||
private CellFormat(Locale locale, String format) { | |||
this.locale = locale; | |||
this.format = format; | |||
CellFormatPart defaultTextFormat = new CellFormatPart(locale, "@"); | |||
Matcher m = ONE_PART.matcher(format); | |||
List<CellFormatPart> parts = new ArrayList<CellFormatPart>(); | |||
@@ -172,7 +197,7 @@ public class CellFormat { | |||
if (valueDesc.endsWith(";")) | |||
valueDesc = valueDesc.substring(0, valueDesc.length() - 1); | |||
parts.add(new CellFormatPart(valueDesc)); | |||
parts.add(new CellFormatPart(locale, valueDesc)); | |||
} catch (RuntimeException e) { | |||
CellFormatter.logger.log(Level.WARNING, | |||
"Invalid format: " + CellFormatter.quote(m.group()), e); | |||
@@ -187,19 +212,19 @@ public class CellFormat { | |||
posNumFmt = parts.get(0); | |||
negNumFmt = null; | |||
zeroNumFmt = null; | |||
textFmt = DEFAULT_TEXT_FORMAT; | |||
textFmt = defaultTextFormat; | |||
break; | |||
case 2: | |||
posNumFmt = parts.get(0); | |||
negNumFmt = parts.get(1); | |||
zeroNumFmt = null; | |||
textFmt = DEFAULT_TEXT_FORMAT; | |||
textFmt = defaultTextFormat; | |||
break; | |||
case 3: | |||
posNumFmt = parts.get(0); | |||
negNumFmt = parts.get(1); | |||
zeroNumFmt = parts.get(2); | |||
textFmt = DEFAULT_TEXT_FORMAT; | |||
textFmt = defaultTextFormat; | |||
break; | |||
case 4: | |||
default: | |||
@@ -384,7 +409,7 @@ public class CellFormat { | |||
|| (posNumFmt.hasCondition() && posNumFmt.applies(val))) { | |||
return posNumFmt; | |||
} else { | |||
return new CellFormatPart("General"); | |||
return new CellFormatPart(locale, "General"); | |||
} | |||
} else if (formatPartCount == 2) { | |||
if ((!posNumFmt.hasCondition() && val >= 0) |
@@ -17,6 +17,7 @@ | |||
package org.apache.poi.ss.format; | |||
import org.apache.poi.hssf.util.HSSFColor; | |||
import org.apache.poi.util.LocaleUtil; | |||
import javax.swing.*; | |||
@@ -173,6 +174,16 @@ public class CellFormatPart { | |||
* @param desc The string to parse. | |||
*/ | |||
public CellFormatPart(String desc) { | |||
this(LocaleUtil.getUserLocale(), desc); | |||
} | |||
/** | |||
* Create an object to represent a format part. | |||
* | |||
* @param locale The locale to use. | |||
* @param desc The string to parse. | |||
*/ | |||
public CellFormatPart(Locale locale, String desc) { | |||
Matcher m = FORMAT_PAT.matcher(desc); | |||
if (!m.matches()) { | |||
throw new IllegalArgumentException("Unrecognized format: " + quote( | |||
@@ -181,7 +192,7 @@ public class CellFormatPart { | |||
color = getColor(m); | |||
condition = getCondition(m); | |||
type = getCellFormatType(m); | |||
format = getFormatter(m); | |||
format = getFormatter(locale, m); | |||
} | |||
/** | |||
@@ -287,7 +298,7 @@ public class CellFormatPart { | |||
* | |||
* @return The formatter. | |||
*/ | |||
private CellFormatter getFormatter(Matcher matcher) { | |||
private CellFormatter getFormatter(Locale locale, Matcher matcher) { | |||
String fdesc = matcher.group(SPECIFICATION_GROUP); | |||
// For now, we don't support localised currencies, so simplify if there | |||
@@ -305,7 +316,7 @@ public class CellFormatPart { | |||
} | |||
// Build a formatter for this simplified string | |||
return type.formatter(fdesc); | |||
return type.formatter(locale, fdesc); | |||
} | |||
/** |
@@ -17,6 +17,8 @@ | |||
package org.apache.poi.ss.format; | |||
import java.util.Locale; | |||
/** | |||
* The different kinds of formats that the formatter understands. | |||
* | |||
@@ -26,11 +28,14 @@ public enum CellFormatType { | |||
/** The general (default) format; also used for <tt>"General"</tt>. */ | |||
GENERAL { | |||
boolean isSpecial(char ch) { | |||
return false; | |||
} | |||
CellFormatter formatter(String pattern) { | |||
return new CellGeneralFormatter(); | |||
} | |||
boolean isSpecial(char ch) { | |||
return false; | |||
CellFormatter formatter(Locale locale, String pattern) { | |||
return new CellGeneralFormatter(locale); | |||
} | |||
}, | |||
/** A numeric format. */ | |||
@@ -41,6 +46,9 @@ public enum CellFormatType { | |||
CellFormatter formatter(String pattern) { | |||
return new CellNumberFormatter(pattern); | |||
} | |||
CellFormatter formatter(Locale locale, String pattern) { | |||
return new CellNumberFormatter(locale, pattern); | |||
} | |||
}, | |||
/** A date format. */ | |||
DATE { | |||
@@ -50,6 +58,9 @@ public enum CellFormatType { | |||
CellFormatter formatter(String pattern) { | |||
return new CellDateFormatter(pattern); | |||
} | |||
CellFormatter formatter(Locale locale, String pattern) { | |||
return new CellDateFormatter(locale, pattern); | |||
} | |||
}, | |||
/** An elapsed time format. */ | |||
ELAPSED { | |||
@@ -59,6 +70,9 @@ public enum CellFormatType { | |||
CellFormatter formatter(String pattern) { | |||
return new CellElapsedFormatter(pattern); | |||
} | |||
CellFormatter formatter(Locale locale, String pattern) { | |||
return new CellElapsedFormatter(pattern); | |||
} | |||
}, | |||
/** A text format. */ | |||
TEXT { | |||
@@ -68,6 +82,9 @@ public enum CellFormatType { | |||
CellFormatter formatter(String pattern) { | |||
return new CellTextFormatter(pattern); | |||
} | |||
CellFormatter formatter(Locale locale, String pattern) { | |||
return new CellTextFormatter(pattern); | |||
} | |||
}; | |||
/** | |||
@@ -88,4 +105,15 @@ public enum CellFormatType { | |||
* @return A new formatter of the appropriate type, for the given pattern. | |||
*/ | |||
abstract CellFormatter formatter(String pattern); | |||
/** | |||
* Returns a new formatter of the appropriate type, for the given pattern. | |||
* The pattern must be appropriate for the type. | |||
* | |||
* @param locale The locale to use. | |||
* @param pattern The pattern to use. | |||
* | |||
* @return A new formatter of the appropriate type, for the given pattern. | |||
*/ | |||
abstract CellFormatter formatter(Locale locale, String pattern); | |||
} |
@@ -16,8 +16,11 @@ | |||
==================================================================== */ | |||
package org.apache.poi.ss.format; | |||
import java.util.Locale; | |||
import java.util.logging.Logger; | |||
import org.apache.poi.util.LocaleUtil; | |||
/** | |||
* This is the abstract supertype for the various cell formatters. | |||
* | |||
@@ -26,6 +29,7 @@ import java.util.logging.Logger; | |||
public abstract class CellFormatter { | |||
/** The original specified format. */ | |||
protected final String format; | |||
protected final Locale locale; | |||
/** | |||
* Creates a new formatter object, storing the format in {@link #format}. | |||
@@ -33,6 +37,17 @@ public abstract class CellFormatter { | |||
* @param format The format. | |||
*/ | |||
public CellFormatter(String format) { | |||
this(LocaleUtil.getUserLocale(), format); | |||
} | |||
/** | |||
* Creates a new formatter object, storing the format in {@link #format}. | |||
* | |||
* @param locale The locale. | |||
* @param format The format. | |||
*/ | |||
public CellFormatter(Locale locale, String format) { | |||
this.locale = locale; | |||
this.format = format; | |||
} | |||
@@ -29,7 +29,11 @@ import org.apache.poi.util.LocaleUtil; | |||
public class CellGeneralFormatter extends CellFormatter { | |||
/** Creates a new general formatter. */ | |||
public CellGeneralFormatter() { | |||
super("General"); | |||
this(LocaleUtil.getUserLocale()); | |||
} | |||
/** Creates a new general formatter. */ | |||
public CellGeneralFormatter(Locale locale) { | |||
super(locale, "General"); | |||
} | |||
/** | |||
@@ -59,9 +63,9 @@ public class CellGeneralFormatter extends CellFormatter { | |||
stripZeros = false; | |||
} | |||
Formatter formatter = new Formatter(toAppendTo, LocaleUtil.getUserLocale()); | |||
Formatter formatter = new Formatter(toAppendTo, locale); | |||
try { | |||
formatter.format(LocaleUtil.getUserLocale(), fmt, value); | |||
formatter.format(locale, fmt, value); | |||
} finally { | |||
formatter.close(); | |||
} |
@@ -26,6 +26,7 @@ import java.util.Formatter; | |||
import java.util.Iterator; | |||
import java.util.List; | |||
import java.util.ListIterator; | |||
import java.util.Locale; | |||
import java.util.Set; | |||
import java.util.TreeSet; | |||
@@ -48,7 +49,7 @@ public class CellNumberFormatter extends CellFormatter { | |||
private final Special numerator; | |||
private final Special afterInteger; | |||
private final Special afterFractional; | |||
private final boolean integerCommas; | |||
private final boolean showGroupingSeparator; | |||
private final List<Special> specials = new ArrayList<Special>(); | |||
private final List<Special> integerSpecials = new ArrayList<Special>(); | |||
private final List<Special> fractionalSpecials = new ArrayList<Special>(); | |||
@@ -69,13 +70,11 @@ public class CellNumberFormatter extends CellFormatter { | |||
// ("#" for integer values, and "#.#" for floating-point values) is | |||
// different from the 'General' format for numbers ("#" for integer | |||
// values and "#.#########" for floating-point values). | |||
private static final CellFormatter SIMPLE_NUMBER = new GeneralNumberFormatter(); | |||
private static final CellFormatter SIMPLE_INT = new CellNumberFormatter("#"); | |||
private static final CellFormatter SIMPLE_FLOAT = new CellNumberFormatter("#.#"); | |||
private final CellFormatter SIMPLE_NUMBER = new GeneralNumberFormatter(locale); | |||
private static class GeneralNumberFormatter extends CellFormatter { | |||
private GeneralNumberFormatter() { | |||
super("General"); | |||
private GeneralNumberFormatter(Locale locale) { | |||
super(locale, "General"); | |||
} | |||
public void formatValue(StringBuffer toAppendTo, Object value) { | |||
@@ -86,7 +85,8 @@ public class CellNumberFormatter extends CellFormatter { | |||
CellFormatter cf; | |||
if (value instanceof Number) { | |||
Number num = (Number) value; | |||
cf = (num.doubleValue() % 1.0 == 0) ? SIMPLE_INT : SIMPLE_FLOAT; | |||
cf = (num.doubleValue() % 1.0 == 0) ? new CellNumberFormatter(locale, "#") : | |||
new CellNumberFormatter(locale, "#.#"); | |||
} else { | |||
cf = CellTextFormatter.SIMPLE_TEXT; | |||
} | |||
@@ -124,7 +124,17 @@ public class CellNumberFormatter extends CellFormatter { | |||
* @param format The format to parse. | |||
*/ | |||
public CellNumberFormatter(String format) { | |||
super(format); | |||
this(LocaleUtil.getUserLocale(), format); | |||
} | |||
/** | |||
* Creates a new cell number formatter. | |||
* | |||
* @param locale The locale to use. | |||
* @param format The format to parse. | |||
*/ | |||
public CellNumberFormatter(Locale locale, String format) { | |||
super(locale, format); | |||
CellNumberPartHandler ph = new CellNumberPartHandler(); | |||
StringBuffer descBuf = CellFormatPart.parseFormat(format, CellFormatType.NUMBER, ph); | |||
@@ -177,7 +187,7 @@ public class CellNumberFormatter extends CellFormatter { | |||
} | |||
double scaleByRef[] = { ph.getScale() }; | |||
integerCommas = interpretIntegerCommas(descBuf, specials, decimalPoint, integerEnd(), fractionalEnd(), scaleByRef); | |||
showGroupingSeparator = interpretIntegerCommas(descBuf, specials, decimalPoint, integerEnd(), fractionalEnd(), scaleByRef); | |||
if (exponent == null) { | |||
scale = scaleByRef[0]; | |||
} else { | |||
@@ -259,14 +269,17 @@ public class CellNumberFormatter extends CellFormatter { | |||
} | |||
fmtBuf.append('E'); | |||
placeZeros(fmtBuf, exponentSpecials.subList(2, exponentSpecials.size())); | |||
DecimalFormatSymbols dfs = DecimalFormatSymbols.getInstance(LocaleUtil.getUserLocale()); | |||
decimalFmt = new DecimalFormat(fmtBuf.toString(), dfs); | |||
decimalFmt = new DecimalFormat(fmtBuf.toString(), getDecimalFormatSymbols()); | |||
printfFmt = null; | |||
} | |||
desc = descBuf.toString(); | |||
} | |||
private DecimalFormatSymbols getDecimalFormatSymbols() { | |||
return DecimalFormatSymbols.getInstance(locale); | |||
} | |||
private static void placeZeros(StringBuffer sb, List<Special> specials) { | |||
for (Special s : specials) { | |||
if (isDigitFmt(s)) { | |||
@@ -436,7 +449,7 @@ public class CellNumberFormatter extends CellFormatter { | |||
} | |||
Set<CellNumberStringMod> mods = new TreeSet<CellNumberStringMod>(); | |||
StringBuffer output = new StringBuffer(desc); | |||
StringBuffer output = new StringBuffer(localiseFormat(desc)); | |||
if (exponent != null) { | |||
writeScientific(value, output, mods); | |||
@@ -444,21 +457,24 @@ public class CellNumberFormatter extends CellFormatter { | |||
writeFraction(value, null, fractional, output, mods); | |||
} else { | |||
StringBuffer result = new StringBuffer(); | |||
Formatter f = new Formatter(result, LocaleUtil.getUserLocale()); | |||
Formatter f = new Formatter(result, locale); | |||
try { | |||
f.format(LocaleUtil.getUserLocale(), printfFmt, value); | |||
f.format(locale, printfFmt, value); | |||
} finally { | |||
f.close(); | |||
} | |||
if (numerator == null) { | |||
writeFractional(result, output); | |||
writeInteger(result, output, integerSpecials, mods, integerCommas); | |||
writeInteger(result, output, integerSpecials, mods, showGroupingSeparator); | |||
} else { | |||
writeFraction(value, result, fractional, output, mods); | |||
} | |||
} | |||
DecimalFormatSymbols dfs = getDecimalFormatSymbols(); | |||
String groupingSeparator = Character.toString(dfs.getGroupingSeparator()); | |||
// Now strip out any remaining '#'s and add any pending text ... | |||
Iterator<CellNumberStringMod> changes = mods.iterator(); | |||
CellNumberStringMod nextChange = (changes.hasNext() ? changes.next() : null); | |||
@@ -478,7 +494,7 @@ public class CellNumberFormatter extends CellFormatter { | |||
switch (nextChange.getOp()) { | |||
case CellNumberStringMod.AFTER: | |||
// ignore adding a comma after a deleted char (which was a '#') | |||
if (nextChange.getToAdd().equals(",") && deletedChars.get(s.pos)) { | |||
if (nextChange.getToAdd().equals(groupingSeparator) && deletedChars.get(s.pos)) { | |||
break; | |||
} | |||
output.insert(modPos + 1, nextChange.getToAdd()); | |||
@@ -545,7 +561,7 @@ public class CellNumberFormatter extends CellFormatter { | |||
StringBuffer result = new StringBuffer(); | |||
FieldPosition fractionPos = new FieldPosition(DecimalFormat.FRACTION_FIELD); | |||
decimalFmt.format(value, result, fractionPos); | |||
writeInteger(result, output, integerSpecials, mods, integerCommas); | |||
writeInteger(result, output, integerSpecials, mods, showGroupingSeparator); | |||
writeFractional(result, output); | |||
/* | |||
@@ -683,6 +699,27 @@ public class CellNumberFormatter extends CellFormatter { | |||
LOG.log(POILogger.ERROR, "error while fraction evaluation", ignored); | |||
} | |||
} | |||
private String localiseFormat(String format) { | |||
DecimalFormatSymbols dfs = getDecimalFormatSymbols(); | |||
if(format.contains(",") && dfs.getGroupingSeparator() != ',') { | |||
if(format.contains(".") && dfs.getDecimalSeparator() != '.') { | |||
format = replaceLast(format, "\\.", "[DECIMAL_SEPARATOR]"); | |||
format = format.replace(',', dfs.getGroupingSeparator()) | |||
.replace("[DECIMAL_SEPARATOR]", Character.toString(dfs.getDecimalSeparator())); | |||
} else { | |||
format = format.replace(',', dfs.getGroupingSeparator()); | |||
} | |||
} else if(format.contains(".") && dfs.getDecimalSeparator() != '.') { | |||
format = format.replace('.', dfs.getDecimalSeparator()); | |||
} | |||
return format; | |||
} | |||
private static String replaceLast(String text, String regex, String replacement) { | |||
return text.replaceFirst("(?s)(.*)" + regex, "$1" + replacement); | |||
} | |||
private static boolean hasChar(char ch, List<Special>... numSpecials) { | |||
for (List<Special> specials : numSpecials) { | |||
@@ -698,9 +735,9 @@ public class CellNumberFormatter extends CellFormatter { | |||
private void writeSingleInteger(String fmt, int num, StringBuffer output, List<Special> numSpecials, Set<CellNumberStringMod> mods) { | |||
StringBuffer sb = new StringBuffer(); | |||
Formatter formatter = new Formatter(sb, LocaleUtil.getUserLocale()); | |||
Formatter formatter = new Formatter(sb, locale); | |||
try { | |||
formatter.format(LocaleUtil.getUserLocale(), fmt, num); | |||
formatter.format(locale, fmt, num); | |||
} finally { | |||
formatter.close(); | |||
} | |||
@@ -709,9 +746,13 @@ public class CellNumberFormatter extends CellFormatter { | |||
private void writeInteger(StringBuffer result, StringBuffer output, | |||
List<Special> numSpecials, Set<CellNumberStringMod> mods, | |||
boolean showCommas) { | |||
boolean showGroupingSeparator) { | |||
DecimalFormatSymbols dfs = getDecimalFormatSymbols(); | |||
String decimalSeparator = Character.toString(dfs.getDecimalSeparator()); | |||
String groupingSeparator = Character.toString(dfs.getGroupingSeparator()); | |||
int pos = result.indexOf(".") - 1; | |||
int pos = result.indexOf(decimalSeparator) - 1; | |||
if (pos < 0) { | |||
if (exponent != null && numSpecials == integerSpecials) { | |||
pos = result.indexOf("E") - 1; | |||
@@ -723,13 +764,13 @@ public class CellNumberFormatter extends CellFormatter { | |||
int strip; | |||
for (strip = 0; strip < pos; strip++) { | |||
char resultCh = result.charAt(strip); | |||
if (resultCh != '0' && resultCh != ',') { | |||
if (resultCh != '0' && resultCh != dfs.getGroupingSeparator()) { | |||
break; | |||
} | |||
} | |||
ListIterator<Special> it = numSpecials.listIterator(numSpecials.size()); | |||
boolean followWithComma = false; | |||
boolean followWithGroupingSeparator = false; | |||
Special lastOutputIntegerDigit = null; | |||
int digit = 0; | |||
while (it.hasPrevious()) { | |||
@@ -741,16 +782,16 @@ public class CellNumberFormatter extends CellFormatter { | |||
resultCh = '0'; | |||
} | |||
Special s = it.previous(); | |||
followWithComma = showCommas && digit > 0 && digit % 3 == 0; | |||
followWithGroupingSeparator = showGroupingSeparator && digit > 0 && digit % 3 == 0; | |||
boolean zeroStrip = false; | |||
if (resultCh != '0' || s.ch == '0' || s.ch == '?' || pos >= strip) { | |||
zeroStrip = s.ch == '?' && pos < strip; | |||
output.setCharAt(s.pos, (zeroStrip ? ' ' : resultCh)); | |||
lastOutputIntegerDigit = s; | |||
} | |||
if (followWithComma) { | |||
mods.add(insertMod(s, zeroStrip ? " " : ",", CellNumberStringMod.AFTER)); | |||
followWithComma = false; | |||
if (followWithGroupingSeparator) { | |||
mods.add(insertMod(s, zeroStrip ? " " : groupingSeparator, CellNumberStringMod.AFTER)); | |||
followWithGroupingSeparator = false; | |||
} | |||
digit++; | |||
--pos; | |||
@@ -761,10 +802,10 @@ public class CellNumberFormatter extends CellFormatter { | |||
// pos was decremented at the end of the loop above when the iterator was at its end | |||
++pos; | |||
extraLeadingDigits = new StringBuffer(result.substring(0, pos)); | |||
if (showCommas) { | |||
if (showGroupingSeparator) { | |||
while (pos > 0) { | |||
if (digit > 0 && digit % 3 == 0) { | |||
extraLeadingDigits.insert(pos, ','); | |||
extraLeadingDigits.insert(pos, groupingSeparator); | |||
} | |||
digit++; | |||
--pos; | |||
@@ -778,7 +819,8 @@ public class CellNumberFormatter extends CellFormatter { | |||
int digit; | |||
int strip; | |||
if (fractionalSpecials.size() > 0) { | |||
digit = result.indexOf(".") + 1; | |||
String decimalSeparator = Character.toString(getDecimalFormatSymbols().getDecimalSeparator()); | |||
digit = result.indexOf(decimalSeparator) + 1; | |||
if (exponent != null) { | |||
strip = result.indexOf("e") - 1; | |||
} else { |
@@ -292,10 +292,6 @@ public class DataFormatter implements Observer { | |||
* @param cell The cell to retrieve a Format for | |||
* @return A Format for the format String | |||
*/ | |||
private Format getFormat(Cell cell) { | |||
return getFormat(cell, null); | |||
} | |||
private Format getFormat(Cell cell, ConditionalFormattingEvaluator cfEvaluator) { | |||
if (cell == null) return null; | |||
@@ -315,12 +311,12 @@ public class DataFormatter implements Observer { | |||
private Format getFormat(double cellValue, int formatIndex, String formatStrIn) { | |||
localeChangedObservable.checkForLocaleChange(); | |||
// // Might be better to separate out the n p and z formats, falling back to p when n and z are not set. | |||
// // That however would require other code to be re factored. | |||
// String[] formatBits = formatStrIn.split(";"); | |||
// int i = cellValue > 0.0 ? 0 : cellValue < 0.0 ? 1 : 2; | |||
// String formatStr = (i < formatBits.length) ? formatBits[i] : formatBits[0]; | |||
// Might be better to separate out the n p and z formats, falling back to p when n and z are not set. | |||
// That however would require other code to be re factored. | |||
// String[] formatBits = formatStrIn.split(";"); | |||
// int i = cellValue > 0.0 ? 0 : cellValue < 0.0 ? 1 : 2; | |||
// String formatStr = (i < formatBits.length) ? formatBits[i] : formatBits[0]; | |||
String formatStr = formatStrIn; | |||
@@ -336,7 +332,7 @@ public class DataFormatter implements Observer { | |||
) ) { | |||
try { | |||
// Ask CellFormat to get a formatter for it | |||
CellFormat cfmt = CellFormat.getInstance(formatStr); | |||
CellFormat cfmt = CellFormat.getInstance(locale, formatStr); | |||
// CellFormat requires callers to identify date vs not, so do so | |||
Object cellValueO = Double.valueOf(cellValue); | |||
if (DateUtil.isADateFormat(formatIndex, formatStr) && | |||
@@ -607,7 +603,7 @@ public class DataFormatter implements Observer { | |||
try { | |||
return new ExcelStyleDateFormatter(formatStr, dateSymbols); | |||
} catch(IllegalArgumentException iae) { | |||
logger.log(POILogger.DEBUG, "Formatting failed for format " + formatStr + ", falling back", iae); | |||
// the pattern could not be parsed correctly, | |||
// so fall back to the default number format | |||
return getDefaultFormat(cellValue); | |||
@@ -718,7 +714,7 @@ public class DataFormatter implements Observer { | |||
setExcelStyleRoundingMode(df); | |||
return df; | |||
} catch(IllegalArgumentException iae) { | |||
logger.log(POILogger.DEBUG, "Formatting failed for format " + formatStr + ", falling back", iae); | |||
// the pattern could not be parsed correctly, | |||
// so fall back to the default number format | |||
return getDefaultFormat(cellValue); |
@@ -811,7 +811,6 @@ public class TestDataFormatter { | |||
CellReference ref = new CellReference("D47"); | |||
Cell cell = wb.getSheetAt(0).getRow(ref.getRow()).getCell(ref.getCol()); | |||
//noinspection deprecation | |||
assertEquals(CellType.FORMULA, cell.getCellTypeEnum()); | |||
assertEquals("G9:K9 I7:I12", cell.getCellFormula()); | |||
@@ -888,18 +887,12 @@ public class TestDataFormatter { | |||
≈ */ | |||
@Test | |||
public void testBug60422() { | |||
//when this is set to Locale.Germany, the result is | |||
LocaleUtil.setUserLocale(Locale.ROOT); | |||
try { | |||
char euro = '\u20AC'; | |||
DataFormatter df = new DataFormatter(Locale.GERMANY); | |||
String formatString = String.format(Locale.ROOT, | |||
"_-* #,##0.00\\ \"%s\"_-;\\-* #,##0.00\\ \"%s\"_-;_-* \"-\"??\\ \"%s\"_-;_-@_-", | |||
euro, euro, euro); | |||
//this should be 4,33 | |||
assertEquals("4.33 " + euro, df.formatRawCellContents(4.33, 178, formatString)); | |||
} finally { | |||
LocaleUtil.resetUserLocale(); | |||
} | |||
char euro = '\u20AC'; | |||
DataFormatter df = new DataFormatter(Locale.GERMANY); | |||
String formatString = String.format(Locale.ROOT, | |||
"_-* #,##0.00\\ \"%s\"_-;\\-* #,##0.00\\ \"%s\"_-;_-* \"-\"??\\ \"%s\"_-;_-@_-", | |||
euro, euro, euro); | |||
assertEquals("4,33 " + euro, df.formatRawCellContents(4.33, 178, formatString)); | |||
assertEquals("1.234,33 " + euro, df.formatRawCellContents(1234.33, 178, formatString)); | |||
} | |||
} |