Code clean-up in HSSFDataFormat etc. Removed bad characters from TestHSSFDataFormatter. Added comment about international formats.

git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@775570 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Josh Micich 2009-05-17 00:10:36 +00:00
parent ad56447d05
commit 508e2c83cb
3 changed files with 329 additions and 319 deletions

View File

@ -23,195 +23,147 @@
*/
package org.apache.poi.hssf.usermodel;
import java.util.*;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;
import java.util.Vector;
import org.apache.poi.hssf.model.Workbook;
import org.apache.poi.hssf.record.FormatRecord;
import org.apache.poi.ss.usermodel.DataFormat;
import org.apache.poi.ss.usermodel.BuiltinFormats;
import org.apache.poi.ss.usermodel.DataFormat;
/**
* Utility to identify builtin formats. Now can handle user defined data formats also. The following is a list of the formats as
* returned by this class.<P>
*<P>
* 0, "General"<br>
* 1, "0"<br>
* 2, "0.00"<br>
* 3, "#,##0"<br>
* 4, "#,##0.00"<br>
* 5, "($#,##0_);($#,##0)"<br>
* 6, "($#,##0_);[Red]($#,##0)"<br>
* 7, "($#,##0.00);($#,##0.00)"<br>
* 8, "($#,##0.00_);[Red]($#,##0.00)"<br>
* 9, "0%"<br>
* 0xa, "0.00%"<br>
* 0xb, "0.00E+00"<br>
* 0xc, "# ?/?"<br>
* 0xd, "# ??/??"<br>
* 0xe, "m/d/yy"<br>
* 0xf, "d-mmm-yy"<br>
* 0x10, "d-mmm"<br>
* 0x11, "mmm-yy"<br>
* 0x12, "h:mm AM/PM"<br>
* 0x13, "h:mm:ss AM/PM"<br>
* 0x14, "h:mm"<br>
* 0x15, "h:mm:ss"<br>
* 0x16, "m/d/yy h:mm"<br>
*<P>
* // 0x17 - 0x24 reserved for international and undocumented
* 0x25, "(#,##0_);(#,##0)"<P>
* 0x26, "(#,##0_);[Red](#,##0)"<P>
* 0x27, "(#,##0.00_);(#,##0.00)"<P>
* 0x28, "(#,##0.00_);[Red](#,##0.00)"<P>
* 0x29, "_(*#,##0_);_(*(#,##0);_(* \"-\"_);_(@_)"<P>
* 0x2a, "_($*#,##0_);_($*(#,##0);_($* \"-\"_);_(@_)"<P>
* 0x2b, "_(*#,##0.00_);_(*(#,##0.00);_(*\"-\"??_);_(@_)"<P>
* 0x2c, "_($*#,##0.00_);_($*(#,##0.00);_($*\"-\"??_);_(@_)"<P>
* 0x2d, "mm:ss"<P>
* 0x2e, "[h]:mm:ss"<P>
* 0x2f, "mm:ss.0"<P>
* 0x30, "##0.0E+0"<P>
* 0x31, "@" - This is text format.<P>
* 0x31 "text" - Alias for "@"<P>
* Identifies both built-in and user defined formats within a workbook.<p/>
* See {@link BuiltinFormats} for a list of supported built-in formats.<p/>
*
* <b>International Formats</b><br/>
* Since version 2003 Excel has supported international formats. These are denoted
* with a prefix "[$-xxx]" (where xxx is a 1-7 digit hexadecimal number).
* See the Microsoft article
* <a href="http://office.microsoft.com/assistance/hfws.aspx?AssetID=HA010346351033&CTT=6&Origin=EC010272491033">
* Creating international number formats
* </a> for more details on these codes.
*
* @author Andrew C. Oliver (acoliver at apache dot org)
* @author Shawn M. Laubach (slaubach at apache dot org)
*/
public final class HSSFDataFormat implements DataFormat {
private static final String[] _builtinFormats = BuiltinFormats.getAll();
public class HSSFDataFormat implements DataFormat
{
private static List builtinFormats = createBuiltinFormats();
private final Vector<String> _formats = new Vector<String>();
private final Workbook _workbook;
private boolean _movedBuiltins = false; // Flag to see if need to
// check the built in list
// or if the regular list
// has all entries.
private Vector formats = new Vector();
private Workbook workbook;
private boolean movedBuiltins = false; // Flag to see if need to
// check the built in list
// or if the regular list
// has all entries.
/**
* Constructs a new data formatter. It takes a workbook to have
* access to the workbooks format records.
* @param workbook the workbook the formats are tied to.
*/
public HSSFDataFormat(Workbook workbook) {
_workbook = workbook;
/**
* Construncts a new data formatter. It takes a workbook to have
* access to the workbooks format records.
* @param workbook the workbook the formats are tied to.
*/
public HSSFDataFormat( Workbook workbook )
{
this.workbook = workbook;
Iterator i = workbook.getFormats().iterator();
while ( i.hasNext() )
{
FormatRecord r = (FormatRecord) i.next();
if ( formats.size() < r.getIndexCode() + 1 )
{
formats.setSize( r.getIndexCode() + 1 );
}
formats.set( r.getIndexCode(), r.getFormatString() );
}
@SuppressWarnings("unchecked")
Iterator<FormatRecord> i = workbook.getFormats().iterator();
while (i.hasNext()) {
FormatRecord r = i.next();
if (_formats.size() < r.getIndexCode() + 1) {
_formats.setSize(r.getIndexCode() + 1);
}
_formats.set(r.getIndexCode(), r.getFormatString());
}
}
}
public static List<String> getBuiltinFormats() {
return Arrays.asList(_builtinFormats);
}
private static synchronized List createBuiltinFormats()
{
List builtinFormats = new Vector();
Map<Integer, String> formats = BuiltinFormats.getBuiltinFormats();
for(int key : formats.keySet()) {
builtinFormats.add(key, formats.get(key));
}
return builtinFormats;
}
/**
* get the format index that matches the given format string<p>
* Automatically converts "text" to excel's format string to represent text.
* @param format string matching a built in format
* @return index of format or -1 if undefined.
*/
public static short getBuiltinFormat(String format) {
return (short) BuiltinFormats.getBuiltinFormat(format);
}
public static List getBuiltinFormats()
{
return builtinFormats;
}
/**
* Get the format index that matches the given format
* string, creating a new format entry if required.
* Aliases text to the proper format as required.
* @param format string matching a built in format
* @return index of format.
*/
public short getFormat(String pFormat) {
/**
* get the format index that matches the given format string<p>
* Automatically converts "text" to excel's format string to represent text.
* @param format string matching a built in format
* @return index of format or -1 if undefined.
*/
String format;
if (pFormat.toUpperCase().equals("TEXT")) {
format = "@";
} else {
format = pFormat;
}
public static short getBuiltinFormat( String format )
{
return (short)BuiltinFormats.getBuiltinFormat(format);
}
if (!_movedBuiltins) {
for (int i=0; i<_builtinFormats.length; i++) {
if (_formats.size() < i + 1) {
_formats.setSize(i + 1);
}
_formats.set(i, _builtinFormats[i]);
}
_movedBuiltins = true;
}
ListIterator<String> i;
i = _formats.listIterator();
int ind;
while (i.hasNext()) {
ind = i.nextIndex();
if (format.equals(i.next())) {
return (short) ind;
}
}
/**
* Get the format index that matches the given format
* string, creating a new format entry if required.
* Aliases text to the proper format as required.
* @param format string matching a built in format
* @return index of format.
*/
public short getFormat(String format) {
ListIterator i;
int ind;
ind = _workbook.getFormat(format, true);
if (_formats.size() <= ind)
_formats.setSize(ind + 1);
_formats.set(ind, format);
if (format.toUpperCase().equals("TEXT"))
format = "@";
return (short) ind;
}
if (!movedBuiltins) {
i = builtinFormats.listIterator();
while (i.hasNext()) {
ind = i.nextIndex();
if (formats.size() < ind + 1) {
formats.setSize(ind + 1);
}
/**
* get the format string that matches the given format index
* @param index of a format
* @return string represented at index of format or null if there is not a format at that index
*/
public String getFormat(short index) {
if (_movedBuiltins) {
return _formats.get(index);
}
if (_builtinFormats.length > index && _builtinFormats[index] != null) {
return _builtinFormats[index];
}
return _formats.get(index);
}
formats.set(ind, i.next());
}
movedBuiltins = true;
}
i = formats.listIterator();
while (i.hasNext()) {
ind = i.nextIndex();
if (format.equals(i.next()))
return (short) ind;
}
/**
* get the format string that matches the given format index
* @param index of a built in format
* @return string represented at index of format or null if there is not a builtin format at that index
*/
public static String getBuiltinFormat(short index) {
return BuiltinFormats.getBuiltinFormat(index);
}
ind = workbook.getFormat(format, true);
if (formats.size() <= ind)
formats.setSize(ind + 1);
formats.set(ind, format);
return (short) ind;
}
/**
* get the format string that matches the given format index
* @param index of a format
* @return string represented at index of format or null if there is not a format at that index
*/
public String getFormat( short index )
{
if ( movedBuiltins )
return (String) formats.get( index );
else
return (String) ( builtinFormats.size() > index
&& builtinFormats.get( index ) != null
? builtinFormats.get( index ) : formats.get( index ) );
}
/**
* get the format string that matches the given format index
* @param index of a built in format
* @return string represented at index of format or null if there is not a builtin format at that index
*/
public static String getBuiltinFormat( short index )
{
return BuiltinFormats.getBuiltinFormat(index);
}
/**
* get the number of builtin and reserved builtinFormats
* @return number of builtin and reserved builtinFormats
*/
public static int getNumberOfBuiltinBuiltinFormats()
{
return BuiltinFormats.getBuiltinFormats().size();
}
/**
* get the number of built-in and reserved builtinFormats
* @return number of built-in and reserved builtinFormats
*/
public static int getNumberOfBuiltinBuiltinFormats() {
return _builtinFormats.length;
}
}

View File

@ -16,118 +16,175 @@
==================================================================== */
package org.apache.poi.ss.usermodel;
import java.util.Map;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
/**
* Utility to identify builtin formats
* Utility to identify built-in formats. The following is a list of the formats as
* returned by this class.<p/>
*<p/>
* 0, "General"<br/>
* 1, "0"<br/>
* 2, "0.00"<br/>
* 3, "#,##0"<br/>
* 4, "#,##0.00"<br/>
* 5, "($#,##0_);($#,##0)"<br/>
* 6, "($#,##0_);[Red]($#,##0)"<br/>
* 7, "($#,##0.00);($#,##0.00)"<br/>
* 8, "($#,##0.00_);[Red]($#,##0.00)"<br/>
* 9, "0%"<br/>
* 0xa, "0.00%"<br/>
* 0xb, "0.00E+00"<br/>
* 0xc, "# ?/?"<br/>
* 0xd, "# ??/??"<br/>
* 0xe, "m/d/yy"<br/>
* 0xf, "d-mmm-yy"<br/>
* 0x10, "d-mmm"<br/>
* 0x11, "mmm-yy"<br/>
* 0x12, "h:mm AM/PM"<br/>
* 0x13, "h:mm:ss AM/PM"<br/>
* 0x14, "h:mm"<br/>
* 0x15, "h:mm:ss"<br/>
* 0x16, "m/d/yy h:mm"<br/>
*<p/>
* // 0x17 - 0x24 reserved for international and undocumented
* 0x25, "(#,##0_);(#,##0)"<br/>
* 0x26, "(#,##0_);[Red](#,##0)"<br/>
* 0x27, "(#,##0.00_);(#,##0.00)"<br/>
* 0x28, "(#,##0.00_);[Red](#,##0.00)"<br/>
* 0x29, "_(*#,##0_);_(*(#,##0);_(* \"-\"_);_(@_)"<br/>
* 0x2a, "_($*#,##0_);_($*(#,##0);_($* \"-\"_);_(@_)"<br/>
* 0x2b, "_(*#,##0.00_);_(*(#,##0.00);_(*\"-\"??_);_(@_)"<br/>
* 0x2c, "_($*#,##0.00_);_($*(#,##0.00);_($*\"-\"??_);_(@_)"<br/>
* 0x2d, "mm:ss"<br/>
* 0x2e, "[h]:mm:ss"<br/>
* 0x2f, "mm:ss.0"<br/>
* 0x30, "##0.0E+0"<br/>
* 0x31, "@" - This is text format.<br/>
* 0x31 "text" - Alias for "@"<br/>
* <p/>
*
* @author Yegor Kozlov
*/
public class BuiltinFormats {
/**
* The first user-defined format starts at 164.
*/
public static final int FIRST_USER_DEFINED_FORMAT_INDEX = 164;
public final class BuiltinFormats {
/**
* The first user-defined format starts at 164.
*/
public static final int FIRST_USER_DEFINED_FORMAT_INDEX = 164;
private final static Map<Integer, String> formats;
private final static String[] _formats;
static {
formats = new LinkedHashMap<Integer, String>();
formats.put( 0, "General" );
formats.put( 1, "0" );
formats.put( 2, "0.00" );
formats.put( 3, "#,##0" );
formats.put( 4, "#,##0.00" );
formats.put( 5, "($#,##0_);($#,##0)" );
formats.put( 6, "($#,##0_);[Red]($#,##0)" );
formats.put( 7, "($#,##0.00);($#,##0.00)" );
formats.put( 8, "($#,##0.00_);[Red]($#,##0.00)" );
formats.put( 9, "0%" );
formats.put( 0xa, "0.00%" );
formats.put( 0xb, "0.00E+00" );
formats.put( 0xc, "# ?/?" );
formats.put( 0xd, "# ??/??" );
formats.put( 0xe, "m/d/yy" );
formats.put( 0xf, "d-mmm-yy" );
formats.put( 0x10, "d-mmm" );
formats.put( 0x11, "mmm-yy" );
formats.put( 0x12, "h:mm AM/PM" );
formats.put( 0x13, "h:mm:ss AM/PM" );
formats.put( 0x14, "h:mm" );
formats.put( 0x15, "h:mm:ss" );
formats.put( 0x16, "m/d/yy h:mm" );
static {
List<String> m = new ArrayList<String>();
putFormat(m, 0, "General");
putFormat(m, 1, "0");
putFormat(m, 2, "0.00");
putFormat(m, 3, "#,##0");
putFormat(m, 4, "#,##0.00");
putFormat(m, 5, "($#,##0_);($#,##0)");
putFormat(m, 6, "($#,##0_);[Red]($#,##0)");
putFormat(m, 7, "($#,##0.00);($#,##0.00)");
putFormat(m, 8, "($#,##0.00_);[Red]($#,##0.00)");
putFormat(m, 9, "0%");
putFormat(m, 0xa, "0.00%");
putFormat(m, 0xb, "0.00E+00");
putFormat(m, 0xc, "# ?/?");
putFormat(m, 0xd, "# ??/??");
putFormat(m, 0xe, "m/d/yy");
putFormat(m, 0xf, "d-mmm-yy");
putFormat(m, 0x10, "d-mmm");
putFormat(m, 0x11, "mmm-yy");
putFormat(m, 0x12, "h:mm AM/PM");
putFormat(m, 0x13, "h:mm:ss AM/PM");
putFormat(m, 0x14, "h:mm");
putFormat(m, 0x15, "h:mm:ss");
putFormat(m, 0x16, "m/d/yy h:mm");
// 0x17 - 0x24 reserved for international and undocumented
formats.put( 0x17, "0x17" );
formats.put( 0x18, "0x18" );
formats.put( 0x19, "0x19" );
formats.put( 0x1a, "0x1a" );
formats.put( 0x1b, "0x1b" );
formats.put( 0x1c, "0x1c" );
formats.put( 0x1d, "0x1d" );
formats.put( 0x1e, "0x1e" );
formats.put( 0x1f, "0x1f" );
formats.put( 0x20, "0x20" );
formats.put( 0x21, "0x21" );
formats.put( 0x22, "0x22" );
formats.put( 0x23, "0x23" );
formats.put( 0x24, "0x24" );
// 0x17 - 0x24 reserved for international and undocumented
for (int i=0x17; i<=0x24; i++) {
// TODO - one junit relies on these values which seems incorrect
putFormat(m, i, "reserved-0x" + Integer.toHexString(i));
}
// 0x17 - 0x24 reserved for international and undocumented
formats.put( 0x25, "(#,##0_);(#,##0)" );
formats.put( 0x26, "(#,##0_);[Red](#,##0)" );
formats.put( 0x27, "(#,##0.00_);(#,##0.00)" );
formats.put( 0x28, "(#,##0.00_);[Red](#,##0.00)" );
formats.put( 0x29, "_(*#,##0_);_(*(#,##0);_(* \"-\"_);_(@_)" );
formats.put( 0x2a, "_($*#,##0_);_($*(#,##0);_($* \"-\"_);_(@_)" );
formats.put( 0x2b, "_(*#,##0.00_);_(*(#,##0.00);_(*\"-\"??_);_(@_)" );
formats.put( 0x2c,
"_($*#,##0.00_);_($*(#,##0.00);_($*\"-\"??_);_(@_)" );
formats.put( 0x2d, "mm:ss" );
formats.put( 0x2e, "[h]:mm:ss" );
formats.put( 0x2f, "mm:ss.0" );
formats.put( 0x30, "##0.0E+0" );
formats.put( 0x31, "@" );
}
putFormat(m, 0x25, "(#,##0_);(#,##0)");
putFormat(m, 0x26, "(#,##0_);[Red](#,##0)");
putFormat(m, 0x27, "(#,##0.00_);(#,##0.00)");
putFormat(m, 0x28, "(#,##0.00_);[Red](#,##0.00)");
putFormat(m, 0x29, "_(*#,##0_);_(*(#,##0);_(* \"-\"_);_(@_)");
putFormat(m, 0x2a, "_($*#,##0_);_($*(#,##0);_($* \"-\"_);_(@_)");
putFormat(m, 0x2b, "_(*#,##0.00_);_(*(#,##0.00);_(*\"-\"??_);_(@_)");
putFormat(m, 0x2c, "_($*#,##0.00_);_($*(#,##0.00);_($*\"-\"??_);_(@_)");
putFormat(m, 0x2d, "mm:ss");
putFormat(m, 0x2e, "[h]:mm:ss");
putFormat(m, 0x2f, "mm:ss.0");
putFormat(m, 0x30, "##0.0E+0");
putFormat(m, 0x31, "@");
String[] ss = new String[m.size()];
m.toArray(ss);
_formats = ss;
}
private static void putFormat(List<String> m, int index, String value) {
if (m.size() != index) {
throw new IllegalStateException("index " + index + " is wrong");
}
m.add(value);
}
/**
* Get the index-formatString map with built-in data formats
*
* @return built-in data formats
*/
public static Map<Integer, String> getBuiltinFormats(){
return formats;
}
/**
* Get the format string that matches the given format index
*
* @param index of a built in format
* @return string represented at index of format or null if there is not a builtin format at that index
*/
public static String getBuiltinFormat(int index){
return formats.get(index);
}
/**
* @deprecated (May 2009) use {@link #getAll()}
*/
public static Map<Integer, String> getBuiltinFormats() {
Map<Integer, String> result = new LinkedHashMap<Integer, String>();
for (int i=0; i<_formats.length; i++) {
result.put(new Integer(i), _formats[i]);
}
return result;
}
/**
* Get the format index that matches the given format string
* <p>
* Automatically converts "text" to excel's format string to represent text.
* </p>
* @param fmt string matching a built-in format
* @return index of format or -1 if undefined.
*/
public static int getBuiltinFormat(String fmt){
int idx = -1;
if (fmt.toUpperCase().equals("TEXT")) fmt = "@";
/**
* @return array of built-in data formats
*/
public static String[] getAll() {
return _formats.clone();
}
for(int key : formats.keySet()) {
if(fmt.equals(formats.get(key))) {
idx = key;
break;
}
}
return idx;
}
/**
* Get the format string that matches the given format index
*
* @param index of a built in format
* @return string represented at index of format or <code>null</code> if there is not a built-in format at that index
*/
public static String getBuiltinFormat(int index) {
if (index < 0 || index >=_formats.length) {
return null;
}
return _formats[index];
}
/**
* Get the format index that matches the given format string
* <p/>
* Automatically converts "text" to excel's format string to represent text.
* </p>
* @param fmt string matching a built-in format
* @return index of format or -1 if undefined.
*/
public static int getBuiltinFormat(String pFmt) {
String fmt;
if (pFmt.equalsIgnoreCase("TEXT")) {
fmt = "@";
} else {
fmt = pFmt;
}
for(int i =0; i< _formats.length; i++) {
if(fmt.equals(_formats[i])) {
return i;
}
}
return -1;
}
}

View File

@ -22,6 +22,7 @@ import java.text.Format;
import java.util.Iterator;
import org.apache.poi.hssf.HSSFTestDataSamples;
import org.apache.poi.ss.usermodel.Cell;
import junit.framework.TestCase;
@ -80,8 +81,8 @@ public final class TestHSSFDataFormatter extends TestCase {
"(#,##0.00_);(#,##0.00)",
"($#,##0.00_);[Red]($#,##0.00)",
"$#,##0.00",
"[$<EFBFBD>-809]#,##0.00",
"[$<EFBFBD>-2] #,##0.00",
"[$-809]#,##0.00", // international format
"[$-2]#,##0.00", // international format
"0000.00000%",
"0.000E+00",
"0.00E+00",
@ -170,10 +171,10 @@ public final class TestHSSFDataFormatter extends TestCase {
public void testGetFormattedCellValueHSSFCell() {
// Valid date formats -- cell values should be date formatted & not "555.555"
HSSFRow row = wb.getSheetAt(0).getRow(0);
Iterator it = row.cellIterator();
Iterator<Cell> it = row.cellIterator();
log("==== VALID DATE FORMATS ====");
while (it.hasNext()) {
HSSFCell cell = (HSSFCell) it.next();
Cell cell = it.next();
log(formatter.formatCellValue(cell));
// should not be equal to "555.555"
@ -256,13 +257,13 @@ public final class TestHSSFDataFormatter extends TestCase {
*/
public void testSetDefaultNumberFormat() {
HSSFRow row = wb.getSheetAt(0).getRow(2);
Iterator it = row.cellIterator();
Iterator<Cell> it = row.cellIterator();
Format defaultFormat = new DecimalFormat("Balance $#,#00.00 USD;Balance -$#,#00.00 USD");
formatter.setDefaultNumberFormat(defaultFormat);
log("\n==== DEFAULT NUMBER FORMAT ====");
while (it.hasNext()) {
HSSFCell cell = (HSSFCell) it.next();
Cell cell = it.next();
cell.setCellValue(cell.getNumericCellValue() * Math.random() / 1000000 - 1000);
log(formatter.formatCellValue(cell));
assertTrue(formatter.formatCellValue(cell).startsWith("Balance "));
@ -274,18 +275,18 @@ public final class TestHSSFDataFormatter extends TestCase {
* A format of "@" means use the general format
*/
public void testGeneralAtFormat() {
HSSFWorkbook workbook = HSSFTestDataSamples.openSampleWorkbook("47154.xls");
HSSFSheet sheet = workbook.getSheetAt(0);
HSSFRow row = sheet.getRow(0);
HSSFCell cellA1 = row.getCell(0);
HSSFWorkbook workbook = HSSFTestDataSamples.openSampleWorkbook("47154.xls");
HSSFSheet sheet = workbook.getSheetAt(0);
HSSFRow row = sheet.getRow(0);
HSSFCell cellA1 = row.getCell(0);
assertEquals(HSSFCell.CELL_TYPE_NUMERIC, cellA1.getCellType());
assertEquals(2345.0, cellA1.getNumericCellValue(), 0.0001);
assertEquals("@", cellA1.getCellStyle().getDataFormatString());
assertEquals(HSSFCell.CELL_TYPE_NUMERIC, cellA1.getCellType());
assertEquals(2345.0, cellA1.getNumericCellValue(), 0.0001);
assertEquals("@", cellA1.getCellStyle().getDataFormatString());
HSSFDataFormatter f = new HSSFDataFormatter();
HSSFDataFormatter f = new HSSFDataFormatter();
assertEquals("2345", f.formatCellValue(cellA1));
assertEquals("2345", f.formatCellValue(cellA1));
}
private static void log(String msg) {