diff options
author | Nick Burch <nick@apache.org> | 2015-10-24 23:34:47 +0000 |
---|---|---|
committer | Nick Burch <nick@apache.org> | 2015-10-24 23:34:47 +0000 |
commit | b3f68c4eb4f81cfda99bc449b922c12abf348ade (patch) | |
tree | b78e23301ec7ed5c825854abe91f8387fba4f964 /src/java/org/apache/poi | |
parent | cbde002fa1356f53b382b97797229ed209ee522f (diff) | |
download | poi-b3f68c4eb4f81cfda99bc449b922c12abf348ade.tar.gz poi-b3f68c4eb4f81cfda99bc449b922c12abf348ade.zip |
#58532 For Excel cell formats with 3+ parts to them (eg +ve,-ve,0), which
DataFormatter didn't properly support, call out to the alternate CellFormat
instead for the formatting.
This also allows us to enable some disabled parts of DataFormatter unit tests
We still need to rationalise DataFormatter and CellFormatter though, so we
only have one set of cell formatting logic...
git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@1710399 13f79535-47bb-0310-9956-ffa450edef68
Diffstat (limited to 'src/java/org/apache/poi')
-rw-r--r-- | src/java/org/apache/poi/ss/usermodel/DataFormatter.java | 65 |
1 files changed, 45 insertions, 20 deletions
diff --git a/src/java/org/apache/poi/ss/usermodel/DataFormatter.java b/src/java/org/apache/poi/ss/usermodel/DataFormatter.java index 2f414a1d9e..add3be8cef 100644 --- a/src/java/org/apache/poi/ss/usermodel/DataFormatter.java +++ b/src/java/org/apache/poi/ss/usermodel/DataFormatter.java @@ -40,8 +40,12 @@ 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.util.NumberToTextConverter; import org.apache.poi.util.LocaleUtil; +import org.apache.poi.util.POILogFactory; +import org.apache.poi.util.POILogger; /** @@ -197,6 +201,9 @@ public class DataFormatter implements Observer { /** the Observable to notify, when the locale has been changed */ private final LocaleChangeObservable localeChangedObervable = new LocaleChangeObservable(); + /** For logging any problems we find */ + private static POILogger logger = POILogFactory.getLogger(DataFormatter.class); + /** * Creates a formatter using the {@link Locale#getDefault() default locale}. */ @@ -270,28 +277,30 @@ public class DataFormatter implements Observer { // String formatStr = (i < formatBits.length) ? formatBits[i] : formatBits[0]; String formatStr = formatStrIn; - // Excel supports positive/negative/zero, but java - // doesn't, so we need to do it specially - final int firstAt = formatStr.indexOf(';'); - final int lastAt = formatStr.lastIndexOf(';'); - // p and p;n are ok by default. p;n;z and p;n;z;s need to be fixed. - if (firstAt != -1 && firstAt != lastAt) { - final int secondAt = formatStr.indexOf(';', firstAt + 1); - if (secondAt == lastAt) { // p;n;z - if (cellValue == 0.0) { - formatStr = formatStr.substring(lastAt + 1); - } else { - formatStr = formatStr.substring(0, lastAt); - } - } else { - if (cellValue == 0.0) { // p;n;z;s - formatStr = formatStr.substring(secondAt + 1, lastAt); - } else { - formatStr = formatStr.substring(0, secondAt); + + // Excel supports 3+ part conditional data formats, eg positive/negative/zero, + // or (>1000),(>0),(0),(negative). As Java doesn't handle these kinds + // of different formats for different ranges, just +ve/-ve, we need to + // handle these ourselves in a special way. + // For now, if we detect 3+ parts, we call out to CellFormat to handle it + // TODO Going forward, we should really merge the logic between the two classes + if (formatStr.indexOf(";") != -1 && + formatStr.indexOf(';') != formatStr.lastIndexOf(';')) { + try { + // Ask CellFormat to get a formatter for it + CellFormat cfmt = CellFormat.getInstance(formatStr); + // CellFormat requires callers to identify date vs not, so do so + Object cellValueO = Double.valueOf(cellValue); + if (DateUtil.isADateFormat(formatIndex, formatStr)) { + cellValueO = DateUtil.getJavaDate(cellValue); } + // Wrap and return (non-cachable - CellFormat does that) + return new CellFormatResultWrapper( cfmt.apply(cellValueO) ); + } catch (Exception e) { + logger.log(POILogger.WARN, "Formatting failed as " + formatStr + ", falling back", e); } } - + // Excel's # with value 0 will output empty where Java will output 0. This hack removes the # from the format. if (emulateCsv && cellValue == 0.0 && formatStr.contains("#") && !formatStr.contains("0")) { formatStr = formatStr.replaceAll("#", ""); @@ -310,7 +319,6 @@ public class DataFormatter implements Observer { // Build a formatter, and cache it format = createFormat(cellValue, formatIndex, formatStr); - formats.put(formatStr, format); return format; } @@ -1116,4 +1124,21 @@ public class DataFormatter implements Observer { return df.parseObject(source, pos); } } + /** + * Workaround until we merge {@link DataFormatter} with {@link CellFormat}. + * Constant, non-cachable wrapper around a {@link CellFormatResult} + */ + @SuppressWarnings("serial") + private static final class CellFormatResultWrapper extends Format { + private final CellFormatResult result; + private CellFormatResultWrapper(CellFormatResult result) { + this.result = result; + } + public StringBuffer format(Object obj, StringBuffer toAppendTo, FieldPosition pos) { + return toAppendTo.append(result.text); + } + public Object parseObject(String source, ParsePosition pos) { + return null; // Not supported + } + } } |