diff --git a/src/documentation/content/xdocs/status.xml b/src/documentation/content/xdocs/status.xml index c0dda1121..bd83e48d6 100644 --- a/src/documentation/content/xdocs/status.xml +++ b/src/documentation/content/xdocs/status.xml @@ -34,7 +34,8 @@ - 52690 - added a getter for length of encrypted data in Ecma and Agile decryptors + 52708 - misc improvements in CellFormat + 52690 - added a getter for length of encrypted data in Ecma and Agile decryptors 52255 - support adding TIFF,EPS and WPG pictures in OOXML documents 52078 - avoid OutOfMemoryError when rendering groupped pictures in HSLF 52745 - fixed XSSFRichtextString.append to preserve leading / trailing spaces diff --git a/src/java/org/apache/poi/ss/format/CellFormat.java b/src/java/org/apache/poi/ss/format/CellFormat.java index 2122c9f6f..c649d55e0 100644 --- a/src/java/org/apache/poi/ss/format/CellFormat.java +++ b/src/java/org/apache/poi/ss/format/CellFormat.java @@ -18,10 +18,12 @@ package org.apache.poi.ss.format; import org.apache.poi.ss.usermodel.Cell; +import org.apache.poi.ss.usermodel.DateUtil; import org.apache.poi.ss.usermodel.DataFormatter; import javax.swing.*; import java.util.ArrayList; +import java.util.Date; import java.util.List; import java.util.Map; import java.util.WeakHashMap; @@ -75,6 +77,7 @@ public class CellFormat { private final CellFormatPart zeroNumFmt; private final CellFormatPart negNumFmt; private final CellFormatPart textFmt; + private final int formatPartCount; private static final Pattern ONE_PART = Pattern.compile( CellFormatPart.FORMAT_PAT.pattern() + "(;|$)", @@ -83,6 +86,20 @@ public class CellFormat { 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 + * pound signs ("#"). + */ + private static final String INVALID_VALUE_FOR_FORMAT = + "###################################################" + + "###################################################" + + "###################################################" + + "###################################################" + + "###################################################"; + + private static String QUOTE = "\""; + /** * Format a value as it would be were no format specified. This is also * used when the format specified is General. @@ -90,14 +107,7 @@ public class CellFormat { public static final CellFormat GENERAL_FORMAT = new CellFormat("General") { @Override public CellFormatResult apply(Object value) { - String text; - if (value == null) { - text = ""; - } else if (value instanceof Number) { - text = CellNumberFormatter.SIMPLE_NUMBER.format(value); - } else { - text = value.toString(); - } + String text = (new CellGeneralFormatter()).format(value); return new CellFormatResult(true, text, null); } }; @@ -117,7 +127,7 @@ public class CellFormat { public static CellFormat getInstance(String format) { CellFormat fmt = formatCache.get(format); if (fmt == null) { - if (format.equals("General")) + if (format.equals("General") || format.equals("@")) fmt = GENERAL_FORMAT; else fmt = new CellFormat(format); @@ -151,28 +161,33 @@ public class CellFormat { parts.add(null); } } - - switch (parts.size()) { + + formatPartCount = parts.size(); + + switch (formatPartCount) { case 1: - posNumFmt = zeroNumFmt = negNumFmt = parts.get(0); + posNumFmt = parts.get(0); + negNumFmt = null; + zeroNumFmt = null; textFmt = DEFAULT_TEXT_FORMAT; break; case 2: - posNumFmt = zeroNumFmt = parts.get(0); + posNumFmt = parts.get(0); negNumFmt = parts.get(1); + zeroNumFmt = null; textFmt = DEFAULT_TEXT_FORMAT; break; case 3: posNumFmt = parts.get(0); - zeroNumFmt = parts.get(1); - negNumFmt = parts.get(2); + negNumFmt = parts.get(1); + zeroNumFmt = parts.get(2); textFmt = DEFAULT_TEXT_FORMAT; break; case 4: default: posNumFmt = parts.get(0); - zeroNumFmt = parts.get(1); - negNumFmt = parts.get(2); + negNumFmt = parts.get(1); + zeroNumFmt = parts.get(2); textFmt = parts.get(3); break; } @@ -191,17 +206,44 @@ public class CellFormat { if (value instanceof Number) { Number num = (Number) value; double val = num.doubleValue(); - if (val > 0) - return posNumFmt.apply(value); - else if (val < 0) + if (val < 0 && + ((formatPartCount == 2 + && !posNumFmt.hasCondition() && !negNumFmt.hasCondition()) + || (formatPartCount == 3 && !negNumFmt.hasCondition()) + || (formatPartCount == 4 && !negNumFmt.hasCondition()))) { + // The negative number format has the negative formatting required, + // e.g. minus sign or brackets, so pass a positive value so that + // the default leading minus sign is not also output return negNumFmt.apply(-val); - else - return zeroNumFmt.apply(value); + } else { + return getApplicableFormatPart(val).apply(val); + } + } else if (value instanceof java.util.Date) { + // Don't know (and can't get) the workbook date windowing (1900 or 1904) + // so assume 1900 date windowing + Double numericValue = DateUtil.getExcelDate((Date) value); + if (DateUtil.isValidExcelDate(numericValue)) { + return getApplicableFormatPart(numericValue).apply(value); + } else { + throw new IllegalArgumentException("value not a valid Excel date"); + } } else { return textFmt.apply(value); } } + /** + * Returns the result of applying the format to the given date. + * + * @param date The date. + * @param numericValue The numeric value for the date. + * + * @return The result, in a {@link CellFormatResult}. + */ + private CellFormatResult apply(Date date, double numericValue) { + return getApplicableFormatPart(numericValue).apply(date); + } + /** * Fetches the appropriate value from the cell, and returns the result of * applying it to the appropriate format. For formula cells, the computed @@ -216,9 +258,18 @@ public class CellFormat { case Cell.CELL_TYPE_BLANK: return apply(""); case Cell.CELL_TYPE_BOOLEAN: - return apply(Boolean.toString(c.getBooleanCellValue())); + return apply(c.getBooleanCellValue()); case Cell.CELL_TYPE_NUMERIC: - return apply(c.getNumericCellValue()); + Double value = c.getNumericCellValue(); + if (getApplicableFormatPart(value).getCellFormatType() == CellFormatType.DATE) { + if (DateUtil.isValidExcelDate(value)) { + return apply(c.getDateCellValue(), value); + } else { + return apply(INVALID_VALUE_FOR_FORMAT); + } + } else { + return apply(value); + } case Cell.CELL_TYPE_STRING: return apply(c.getStringCellValue()); default: @@ -244,6 +295,25 @@ public class CellFormat { return result; } + /** + * Uses the result of applying this format to the given date, setting the text + * and color of a label before returning the result. + * + * @param label The label to apply to. + * @param date The date. + * @param numericValue The numeric value for the date. + * + * @return The result, in a {@link CellFormatResult}. + */ + private CellFormatResult apply(JLabel label, Date date, double numericValue) { + CellFormatResult result = apply(date, numericValue); + label.setText(result.text); + if (result.textColor != null) { + label.setForeground(result.textColor); + } + return result; + } + /** * Fetches the appropriate value from the cell, and uses the result, setting * the text and color of a label before returning the result. @@ -258,9 +328,18 @@ public class CellFormat { case Cell.CELL_TYPE_BLANK: return apply(label, ""); case Cell.CELL_TYPE_BOOLEAN: - return apply(Boolean.toString(c.getBooleanCellValue())); + return apply(label, c.getBooleanCellValue()); case Cell.CELL_TYPE_NUMERIC: - return apply(label, c.getNumericCellValue()); + Double value = c.getNumericCellValue(); + if (getApplicableFormatPart(value).getCellFormatType() == CellFormatType.DATE) { + if (DateUtil.isValidExcelDate(value)) { + return apply(label, c.getDateCellValue(), value); + } else { + return apply(label, INVALID_VALUE_FOR_FORMAT); + } + } else { + return apply(label, value); + } case Cell.CELL_TYPE_STRING: return apply(label, c.getStringCellValue()); default: @@ -268,6 +347,56 @@ public class CellFormat { } } + /** + * Returns the {@link CellFormatPart} that applies to the value. Result + * depends on how many parts the cell format has, the cell value and any + * conditions. The value must be a {@link Number}. + * + * @param value The value. + * @return The {@link CellFormatPart} that applies to the value. + */ + private CellFormatPart getApplicableFormatPart(Object value) { + + if (value instanceof Number) { + + double val = ((Number) value).doubleValue(); + + if (formatPartCount == 1) { + if (!posNumFmt.hasCondition() + || (posNumFmt.hasCondition() && posNumFmt.applies(val))) { + return posNumFmt; + } else { + return new CellFormatPart("General"); + } + } else if (formatPartCount == 2) { + if ((!posNumFmt.hasCondition() && val >= 0) + || (posNumFmt.hasCondition() && posNumFmt.applies(val))) { + return posNumFmt; + } else if (!negNumFmt.hasCondition() + || (negNumFmt.hasCondition() && negNumFmt.applies(val))) { + return negNumFmt; + } else { + // Return ###...### (255 #s) to match Excel 2007 behaviour + return new CellFormatPart(QUOTE + INVALID_VALUE_FOR_FORMAT + QUOTE); + } + } else { + if ((!posNumFmt.hasCondition() && val > 0) + || (posNumFmt.hasCondition() && posNumFmt.applies(val))) { + return posNumFmt; + } else if ((!negNumFmt.hasCondition() && val < 0) + || (negNumFmt.hasCondition() && negNumFmt.applies(val))) { + return negNumFmt; + // Only the first two format parts can have conditions + } else { + return zeroNumFmt; + } + } + } else { + throw new IllegalArgumentException("value must be a Number"); + } + + } + /** * Returns the ultimate cell type, following the results of formulas. If * the cell is a {@link Cell#CELL_TYPE_FORMULA}, this returns the result of @@ -314,4 +443,4 @@ public class CellFormat { public int hashCode() { return format.hashCode(); } -} \ No newline at end of file +} diff --git a/src/java/org/apache/poi/ss/format/CellFormatPart.java b/src/java/org/apache/poi/ss/format/CellFormatPart.java index f78049a4c..b91307bfc 100644 --- a/src/java/org/apache/poi/ss/format/CellFormatPart.java +++ b/src/java/org/apache/poi/ss/format/CellFormatPart.java @@ -48,6 +48,7 @@ public class CellFormatPart { private final Color color; private CellFormatCondition condition; private final CellFormatter format; + private final CellFormatType type; private static final Map NAMED_COLORS; @@ -167,6 +168,7 @@ public class CellFormatPart { } color = getColor(m); condition = getCondition(m); + type = getCellFormatType(m); format = getFormatter(m); } @@ -174,7 +176,7 @@ public class CellFormatPart { * Returns true if this format part applies to the given value. If * the value is a number and this is part has a condition, returns * true only if the number passes the condition. Otherwise, this - * allways return true. + * always return true. * * @param valueObject The value to evaluate. * @@ -252,6 +254,19 @@ public class CellFormatPart { CONDITION_OPERATOR_GROUP), m.group(CONDITION_VALUE_GROUP)); } + /** + * Returns the CellFormatType object implied by the format specification for + * the format part. + * + * @param matcher The matcher for the format part. + * + * @return The CellFormatType. + */ + private CellFormatType getCellFormatType(Matcher matcher) { + String fdesc = matcher.group(SPECIFICATION_GROUP); + return formatType(fdesc); + } + /** * Returns the formatter object implied by the format specification for the * format part. @@ -262,7 +277,6 @@ public class CellFormatPart { */ private CellFormatter getFormatter(Matcher matcher) { String fdesc = matcher.group(SPECIFICATION_GROUP); - CellFormatType type = formatType(fdesc); return type.formatter(fdesc); } @@ -394,6 +408,25 @@ public class CellFormatPart { return result; } + /** + * Returns the CellFormatType object implied by the format specification for + * the format part. + * + * @return The CellFormatType. + */ + CellFormatType getCellFormatType() { + return type; + } + + /** + * Returns true if this format part has a condition. + * + * @return true if this format part has a condition. + */ + boolean hasCondition() { + return condition != null; + } + public static StringBuffer parseFormat(String fdesc, CellFormatType type, PartHandler partHandler) { @@ -490,4 +523,4 @@ public class CellFormatPart { String str = m.group(g); return (str == null ? "" : str); } -} \ No newline at end of file +} diff --git a/src/java/org/apache/poi/ss/format/CellGeneralFormatter.java b/src/java/org/apache/poi/ss/format/CellGeneralFormatter.java index e2adc61c0..e00a54c90 100644 --- a/src/java/org/apache/poi/ss/format/CellGeneralFormatter.java +++ b/src/java/org/apache/poi/ss/format/CellGeneralFormatter.java @@ -72,6 +72,8 @@ public class CellGeneralFormatter extends CellFormatter { toAppendTo.deleteCharAt(removeFrom--); } } + } else if (value instanceof Boolean) { + toAppendTo.append(value.toString().toUpperCase()); } else { toAppendTo.append(value.toString()); } @@ -81,4 +83,4 @@ public class CellGeneralFormatter extends CellFormatter { public void simpleValue(StringBuffer toAppendTo, Object value) { formatValue(toAppendTo, value); } -} \ No newline at end of file +} diff --git a/src/java/org/apache/poi/ss/format/CellNumberFormatter.java b/src/java/org/apache/poi/ss/format/CellNumberFormatter.java index 8276afda4..91f0979a0 100644 --- a/src/java/org/apache/poi/ss/format/CellNumberFormatter.java +++ b/src/java/org/apache/poi/ss/format/CellNumberFormatter.java @@ -60,6 +60,13 @@ public class CellNumberFormatter extends CellFormatter { private boolean improperFraction; private DecimalFormat decimalFmt; + // The CellNumberFormatter.simpleValue() method uses the SIMPLE_NUMBER + // CellFormatter defined here. The CellFormat.GENERAL_FORMAT CellFormat + // no longer uses the SIMPLE_NUMBER CellFormatter. + // Note that the simpleValue()/SIMPLE_NUMBER CellFormatter format + // ("#" for integer values, and "#.#" for floating-point values) is + // different from the 'General' format for numbers ("#" for integer + // values and "#.#########" for floating-point values). static final CellFormatter SIMPLE_NUMBER = new CellFormatter("General") { public void formatValue(StringBuffer toAppendTo, Object value) { if (value == null) @@ -554,7 +561,13 @@ public class CellNumberFormatter extends CellFormatter { double value = ((Number) valueObject).doubleValue(); value *= scale; - // the '-' sign goes at the front, always, so we pick it out + // For negative numbers: + // - If the cell format has a negative number format, this method + // is called with a positive value and the number format has + // the negative formatting required, e.g. minus sign or brackets. + // - If the cell format does not have a negative number format, + // this method is called with a negative value and the number is + // formatted with a minus sign at the start. boolean negative = value < 0; if (negative) value = -value; @@ -1082,4 +1095,4 @@ public class CellNumberFormatter extends CellFormatter { } -} \ No newline at end of file +} diff --git a/src/java/org/apache/poi/ss/format/CellTextFormatter.java b/src/java/org/apache/poi/ss/format/CellTextFormatter.java index ebefa9847..65cef64de 100644 --- a/src/java/org/apache/poi/ss/format/CellTextFormatter.java +++ b/src/java/org/apache/poi/ss/format/CellTextFormatter.java @@ -61,6 +61,9 @@ public class CellTextFormatter extends CellFormatter { public void formatValue(StringBuffer toAppendTo, Object obj) { int start = toAppendTo.length(); String text = obj.toString(); + if (obj instanceof Boolean) { + text = text.toUpperCase(); + } toAppendTo.append(desc); for (int i = 0; i < textPos.length; i++) { int pos = start + textPos[i]; @@ -76,4 +79,4 @@ public class CellTextFormatter extends CellFormatter { public void simpleValue(StringBuffer toAppendTo, Object value) { SIMPLE_TEXT.formatValue(toAppendTo, value); } -} \ No newline at end of file +} diff --git a/src/ooxml/testcases/org/apache/poi/ss/format/TestCellFormatPart.java b/src/ooxml/testcases/org/apache/poi/ss/format/TestCellFormatPart.java index bd518369d..9fd6664ad 100644 --- a/src/ooxml/testcases/org/apache/poi/ss/format/TestCellFormatPart.java +++ b/src/ooxml/testcases/org/apache/poi/ss/format/TestCellFormatPart.java @@ -37,7 +37,7 @@ public class TestCellFormatPart extends CellFormatTestBase { public Object getValue(Cell cell) { int type = CellFormat.ultimateType(cell); if (type == Cell.CELL_TYPE_BOOLEAN) - return cell.getBooleanCellValue() ? "TRUE" : "FALSE"; + return cell.getBooleanCellValue(); else if (type == Cell.CELL_TYPE_NUMERIC) return cell.getNumericCellValue(); else @@ -93,7 +93,7 @@ public class TestCellFormatPart extends CellFormatTestBase { runFormatTests("TextFormatTests.xlsx", new CellValue() { public Object getValue(Cell cell) { if (CellFormat.ultimateType(cell) == Cell.CELL_TYPE_BOOLEAN) - return cell.getBooleanCellValue() ? "TRUE" : "FALSE"; + return cell.getBooleanCellValue(); else return cell.getStringCellValue(); } @@ -123,4 +123,4 @@ public class TestCellFormatPart extends CellFormatTestBase { } return Double.valueOf(sb.toString()); } -} \ No newline at end of file +} diff --git a/src/testcases/org/apache/poi/ss/format/TestCellFormat.java b/src/testcases/org/apache/poi/ss/format/TestCellFormat.java index 3e0b1507f..fdc57f4ea 100644 --- a/src/testcases/org/apache/poi/ss/format/TestCellFormat.java +++ b/src/testcases/org/apache/poi/ss/format/TestCellFormat.java @@ -16,17 +16,813 @@ ==================================================================== */ package org.apache.poi.ss.format; -import org.apache.poi.ss.format.CellFormat; +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.util.Date; import javax.swing.*; +import org.apache.poi.hssf.usermodel.HSSFWorkbook; +import org.apache.poi.ss.usermodel.Cell; +import org.apache.poi.ss.usermodel.DateUtil; +import org.apache.poi.ss.usermodel.Row; +import org.apache.poi.ss.usermodel.Sheet; +import org.apache.poi.ss.usermodel.Workbook; + import junit.framework.TestCase; public class TestCellFormat extends TestCase { + + private static final String _255_POUND_SIGNS; + static { + StringBuilder sb = new StringBuilder(); + for (int i = 1; i <= 255; i++) { + sb.append('#'); + } + _255_POUND_SIGNS = sb.toString(); + } + public void testSome() { JLabel l = new JLabel(); CellFormat fmt = CellFormat.getInstance( "\"$\"#,##0.00_);[Red]\\(\"$\"#,##0.00\\)"); fmt.apply(l, 1.1); } + + public void testPositiveFormatHasOnePart() { + CellFormat fmt = CellFormat.getInstance("0.00"); + CellFormatResult result = fmt.apply(12.345); + assertEquals("12.35", result.text); + } + + public void testNegativeFormatHasOnePart() { + CellFormat fmt = CellFormat.getInstance("0.00"); + CellFormatResult result = fmt.apply(-12.345); + assertEquals("-12.35", result.text); + } + + public void testZeroFormatHasOnePart() { + CellFormat fmt = CellFormat.getInstance("0.00"); + CellFormatResult result = fmt.apply(0.0); + assertEquals("0.00", result.text); + } + + public void testPositiveFormatHasPosAndNegParts() { + CellFormat fmt = CellFormat.getInstance("0.00;-0.00"); + CellFormatResult result = fmt.apply(12.345); + assertEquals("12.35", result.text); + } + + public void testNegativeFormatHasPosAndNegParts() { + CellFormat fmt = CellFormat.getInstance("0.00;-0.00"); + CellFormatResult result = fmt.apply(-12.345); + assertEquals("-12.35", result.text); + } + + public void testNegativeFormatHasPosAndNegParts2() { + CellFormat fmt = CellFormat.getInstance("0.00;(0.00)"); + CellFormatResult result = fmt.apply(-12.345); + assertEquals("(12.35)", result.text); + } + + public void testZeroFormatHasPosAndNegParts() { + CellFormat fmt = CellFormat.getInstance("0.00;-0.00"); + CellFormatResult result = fmt.apply(0.0); + assertEquals("0.00", result.text); + } + + public void testFormatWithThreeSections() { + CellFormat fmt = CellFormat.getInstance("0.00;-0.00;-"); + + assertEquals("12.35", fmt.apply(12.345).text); + assertEquals("-12.35", fmt.apply(-12.345).text); + assertEquals("-", fmt.apply(0.0).text); + assertEquals("abc", fmt.apply("abc").text); + } + + public void testFormatWithFourSections() { + CellFormat fmt = CellFormat.getInstance("0.00;-0.00;-; @ "); + + assertEquals("12.35", fmt.apply(12.345).text); + assertEquals("-12.35", fmt.apply(-12.345).text); + assertEquals("-", fmt.apply(0.0).text); + assertEquals(" abc ", fmt.apply("abc").text); + } + + public void testApplyCellForGeneralFormat() { + + // Create a workbook, row and cell to test with + Workbook wb = new HSSFWorkbook(); + Sheet sheet = wb.createSheet(); + Row row = sheet.createRow(0); + Cell cell0 = row.createCell(0); + Cell cell1 = row.createCell(1); + Cell cell2 = row.createCell(2); + Cell cell3 = row.createCell(3); + Cell cell4 = row.createCell(4); + + CellFormat cf = CellFormat.getInstance("General"); + + // case Cell.CELL_TYPE_BLANK + CellFormatResult result0 = cf.apply(cell0); + assertEquals("", result0.text); + + // case Cell.CELL_TYPE_BOOLEAN + cell1.setCellValue(true); + CellFormatResult result1 = cf.apply(cell1); + assertEquals("TRUE", result1.text); + + // case Cell.CELL_TYPE_NUMERIC + cell2.setCellValue(1.23); + CellFormatResult result2 = cf.apply(cell2); + assertEquals("1.23", result2.text); + + cell3.setCellValue(123.0); + CellFormatResult result3 = cf.apply(cell3); + assertEquals("123", result3.text); + + // case Cell.CELL_TYPE_STRING + cell4.setCellValue("abc"); + CellFormatResult result4 = cf.apply(cell4); + assertEquals("abc", result4.text); + + } + + public void testApplyCellForAtFormat() { + + // Create a workbook, row and cell to test with + Workbook wb = new HSSFWorkbook(); + Sheet sheet = wb.createSheet(); + Row row = sheet.createRow(0); + Cell cell0 = row.createCell(0); + Cell cell1 = row.createCell(1); + Cell cell2 = row.createCell(2); + Cell cell3 = row.createCell(3); + Cell cell4 = row.createCell(4); + + CellFormat cf = CellFormat.getInstance("@"); + + // case Cell.CELL_TYPE_BLANK + CellFormatResult result0 = cf.apply(cell0); + assertEquals("", result0.text); + + // case Cell.CELL_TYPE_BOOLEAN + cell1.setCellValue(true); + CellFormatResult result1 = cf.apply(cell1); + assertEquals("TRUE", result1.text); + + // case Cell.CELL_TYPE_NUMERIC + cell2.setCellValue(1.23); + CellFormatResult result2 = cf.apply(cell2); + assertEquals("1.23", result2.text); + + cell3.setCellValue(123.0); + CellFormatResult result3 = cf.apply(cell3); + assertEquals("123", result3.text); + + // case Cell.CELL_TYPE_STRING + cell4.setCellValue("abc"); + CellFormatResult result4 = cf.apply(cell4); + assertEquals("abc", result4.text); + + } + + public void testApplyCellForDateFormat() { + + // Create a workbook, row and cell to test with + Workbook wb = new HSSFWorkbook(); + Sheet sheet = wb.createSheet(); + Row row = sheet.createRow(0); + Cell cell0 = row.createCell(0); + Cell cell1 = row.createCell(1); + + CellFormat cf = CellFormat.getInstance("dd/mm/yyyy"); + + cell0.setCellValue(10); + CellFormatResult result0 = cf.apply(cell0); + assertEquals("10/01/1900", result0.text); + + cell1.setCellValue(-1); + CellFormatResult result1 = cf.apply(cell1); + assertEquals(_255_POUND_SIGNS, result1.text); + + } + + public void testApplyCellForTimeFormat() { + + // Create a workbook, row and cell to test with + Workbook wb = new HSSFWorkbook(); + Sheet sheet = wb.createSheet(); + Row row = sheet.createRow(0); + Cell cell = row.createCell(0); + + CellFormat cf = CellFormat.getInstance("hh:mm"); + + cell.setCellValue(DateUtil.convertTime("03:04:05")); + CellFormatResult result = cf.apply(cell); + assertEquals("03:04", result.text); + + } + + public void testApplyCellForDateFormatAndNegativeFormat() { + + // Create a workbook, row and cell to test with + Workbook wb = new HSSFWorkbook(); + Sheet sheet = wb.createSheet(); + Row row = sheet.createRow(0); + Cell cell0 = row.createCell(0); + Cell cell1 = row.createCell(1); + + CellFormat cf = CellFormat.getInstance("dd/mm/yyyy;(0)"); + + cell0.setCellValue(10); + CellFormatResult result0 = cf.apply(cell0); + assertEquals("10/01/1900", result0.text); + + cell1.setCellValue(-1); + CellFormatResult result1 = cf.apply(cell1); + assertEquals("(1)", result1.text); + + } + + public void testApplyJLabelCellForGeneralFormat() { + + // Create a workbook, row and cell to test with + Workbook wb = new HSSFWorkbook(); + Sheet sheet = wb.createSheet(); + Row row = sheet.createRow(0); + Cell cell0 = row.createCell(0); + Cell cell1 = row.createCell(1); + Cell cell2 = row.createCell(2); + Cell cell3 = row.createCell(3); + Cell cell4 = row.createCell(4); + + CellFormat cf = CellFormat.getInstance("General"); + + JLabel label0 = new JLabel(); + JLabel label1 = new JLabel(); + JLabel label2 = new JLabel(); + JLabel label3 = new JLabel(); + JLabel label4 = new JLabel(); + + // case Cell.CELL_TYPE_BLANK + CellFormatResult result0 = cf.apply(label0, cell0); + assertEquals("", result0.text); + assertEquals("", label0.getText()); + + // case Cell.CELL_TYPE_BOOLEAN + cell1.setCellValue(true); + CellFormatResult result1 = cf.apply(label1, cell1); + assertEquals("TRUE", result1.text); + assertEquals("TRUE", label1.getText()); + + // case Cell.CELL_TYPE_NUMERIC + cell2.setCellValue(1.23); + CellFormatResult result2 = cf.apply(label2, cell2); + assertEquals("1.23", result2.text); + assertEquals("1.23", label2.getText()); + + cell3.setCellValue(123.0); + CellFormatResult result3 = cf.apply(label3, cell3); + assertEquals("123", result3.text); + assertEquals("123", label3.getText()); + + // case Cell.CELL_TYPE_STRING + cell4.setCellValue("abc"); + CellFormatResult result4 = cf.apply(label4, cell4); + assertEquals("abc", result4.text); + assertEquals("abc", label4.getText()); + + } + + public void testApplyJLabelCellForAtFormat() { + + // Create a workbook, row and cell to test with + Workbook wb = new HSSFWorkbook(); + Sheet sheet = wb.createSheet(); + Row row = sheet.createRow(0); + Cell cell0 = row.createCell(0); + Cell cell1 = row.createCell(1); + Cell cell2 = row.createCell(2); + Cell cell3 = row.createCell(3); + Cell cell4 = row.createCell(4); + + CellFormat cf = CellFormat.getInstance("@"); + + JLabel label0 = new JLabel(); + JLabel label1 = new JLabel(); + JLabel label2 = new JLabel(); + JLabel label3 = new JLabel(); + JLabel label4 = new JLabel(); + + // case Cell.CELL_TYPE_BLANK + CellFormatResult result0 = cf.apply(label0, cell0); + assertEquals("", result0.text); + assertEquals("", label0.getText()); + + // case Cell.CELL_TYPE_BOOLEAN + cell1.setCellValue(true); + CellFormatResult result1 = cf.apply(label1, cell1); + assertEquals("TRUE", result1.text); + assertEquals("TRUE", label1.getText()); + + // case Cell.CELL_TYPE_NUMERIC + cell2.setCellValue(1.23); + CellFormatResult result2 = cf.apply(label2, cell2); + assertEquals("1.23", result2.text); + assertEquals("1.23", label2.getText()); + + cell3.setCellValue(123.0); + CellFormatResult result3 = cf.apply(label3, cell3); + assertEquals("123", result3.text); + assertEquals("123", label3.getText()); + + // case Cell.CELL_TYPE_STRING + cell4.setCellValue("abc"); + CellFormatResult result4 = cf.apply(label4, cell4); + assertEquals("abc", result4.text); + assertEquals("abc", label4.getText()); + + } + + public void testApplyJLabelCellForDateFormat() { + + // Create a workbook, row and cell to test with + Workbook wb = new HSSFWorkbook(); + Sheet sheet = wb.createSheet(); + Row row = sheet.createRow(0); + Cell cell0 = row.createCell(0); + Cell cell1 = row.createCell(1); + + CellFormat cf = CellFormat.getInstance("dd/mm/yyyy"); + + JLabel label0 = new JLabel(); + JLabel label1 = new JLabel(); + + cell0.setCellValue(10); + CellFormatResult result0 = cf.apply(label0, cell0); + assertEquals("10/01/1900", result0.text); + assertEquals("10/01/1900", label0.getText()); + + cell1.setCellValue(-1); + CellFormatResult result1 = cf.apply(label1, cell1); + assertEquals(_255_POUND_SIGNS, result1.text); + assertEquals(_255_POUND_SIGNS, label1.getText()); + + } + + public void testApplyJLabelCellForTimeFormat() { + + // Create a workbook, row and cell to test with + Workbook wb = new HSSFWorkbook(); + Sheet sheet = wb.createSheet(); + Row row = sheet.createRow(0); + Cell cell = row.createCell(0); + + CellFormat cf = CellFormat.getInstance("hh:mm"); + + JLabel label = new JLabel(); + + cell.setCellValue(DateUtil.convertTime("03:04:05")); + CellFormatResult result = cf.apply(label, cell); + assertEquals("03:04", result.text); + assertEquals("03:04", label.getText()); + + } + + public void testApplyJLabelCellForDateFormatAndNegativeFormat() { + + // Create a workbook, row and cell to test with + Workbook wb = new HSSFWorkbook(); + Sheet sheet = wb.createSheet(); + Row row = sheet.createRow(0); + Cell cell0 = row.createCell(0); + Cell cell1 = row.createCell(1); + + CellFormat cf = CellFormat.getInstance("dd/mm/yyyy;(0)"); + + JLabel label0 = new JLabel(); + JLabel label1 = new JLabel(); + + cell0.setCellValue(10); + CellFormatResult result0 = cf.apply(label0, cell0); + assertEquals("10/01/1900", result0.text); + assertEquals("10/01/1900", label0.getText()); + + cell1.setCellValue(-1); + CellFormatResult result1 = cf.apply(label1, cell1); + assertEquals("(1)", result1.text); + assertEquals("(1)", label1.getText()); + + } + + public void testApplyFormatHasOnePartAndPartHasCondition() { + + // Create a workbook, row and cell to test with + Workbook wb = new HSSFWorkbook(); + Sheet sheet = wb.createSheet(); + Row row = sheet.createRow(0); + Cell cell = row.createCell(0); + + CellFormat cf = CellFormat.getInstance("[>=100]0.00"); + + cell.setCellValue(100); + assertEquals("100.00", cf.apply(cell).text); + + cell.setCellValue(10); + assertEquals("10", cf.apply(cell).text); + + cell.setCellValue(0.123456789012345); + assertEquals("0.123456789", cf.apply(cell).text); + + cell.setCellValue(0); + assertEquals("0", cf.apply(cell).text); + + cell.setCellValue("abc"); + assertEquals("abc", cf.apply(cell).text); + + } + + public void testApplyFormatHasTwoPartsFirstHasCondition() { + + // Create a workbook, row and cell to test with + Workbook wb = new HSSFWorkbook(); + Sheet sheet = wb.createSheet(); + Row row = sheet.createRow(0); + Cell cell = row.createCell(0); + + CellFormat cf = CellFormat.getInstance("[>=100]0.00;0.000"); + + cell.setCellValue(100); + assertEquals("100.00", cf.apply(cell).text); + + cell.setCellValue(10); + assertEquals("10.000", cf.apply(cell).text); + + cell.setCellValue(0.123456789012345); + assertEquals("0.123", cf.apply(cell).text); + + cell.setCellValue(0); + assertEquals("0.000", cf.apply(cell).text); + + cell.setCellValue(-10); + assertEquals("-10.000", cf.apply(cell).text); + + cell.setCellValue("abc"); + assertEquals("abc", cf.apply(cell).text); + + cell.setCellValue("TRUE"); + assertEquals("TRUE", cf.apply(cell).text); + + } + + public void testApplyFormatHasTwoPartsBothHaveCondition() { + + // Create a workbook, row and cell to test with + Workbook wb = new HSSFWorkbook(); + Sheet sheet = wb.createSheet(); + Row row = sheet.createRow(0); + Cell cell = row.createCell(0); + + CellFormat cf = CellFormat.getInstance("[>=100]0.00;[>=10]0.000"); + + cell.setCellValue(100); + assertEquals("100.00", cf.apply(cell).text); + + cell.setCellValue(10); + assertEquals("10.000", cf.apply(cell).text); + + cell.setCellValue(0); + assertEquals(_255_POUND_SIGNS, cf.apply(cell).text); + + cell.setCellValue(-0.123456789012345); + assertEquals(_255_POUND_SIGNS, cf.apply(cell).text); + + cell.setCellValue(-10); + assertEquals(_255_POUND_SIGNS, cf.apply(cell).text); + + cell.setCellValue("abc"); + assertEquals("abc", cf.apply(cell).text); + + } + + public void testApplyFormatHasThreePartsFirstHasCondition() { + + // Create a workbook, row and cell to test with + Workbook wb = new HSSFWorkbook(); + Sheet sheet = wb.createSheet(); + Row row = sheet.createRow(0); + Cell cell = row.createCell(0); + + CellFormat cf = CellFormat.getInstance("[>=100]0.00;0.000;0.0000"); + + cell.setCellValue(100); + assertEquals("100.00", cf.apply(cell).text); + + cell.setCellValue(10); + assertEquals("10.0000", cf.apply(cell).text); + + cell.setCellValue(0.123456789012345); + assertEquals("0.1235", cf.apply(cell).text); + + cell.setCellValue(0); + assertEquals("0.0000", cf.apply(cell).text); + + // Second format part ('0.000') is used for negative numbers + // so result does not have a minus sign + cell.setCellValue(-10); + assertEquals("10.000", cf.apply(cell).text); + + cell.setCellValue("abc"); + assertEquals("abc", cf.apply(cell).text); + + } + + public void testApplyFormatHasThreePartsFirstTwoHaveCondition() { + + // Create a workbook, row and cell to test with + Workbook wb = new HSSFWorkbook(); + Sheet sheet = wb.createSheet(); + Row row = sheet.createRow(0); + Cell cell = row.createCell(0); + + CellFormat cf = CellFormat.getInstance("[>=100]0.00;[>=10]0.000;0.0000"); + + cell.setCellValue(100); + assertEquals("100.00", cf.apply(cell).text); + + cell.setCellValue(10); + assertEquals("10.000", cf.apply(cell).text); + + cell.setCellValue(0); + assertEquals("0.0000", cf.apply(cell).text); + + cell.setCellValue(-10); + assertEquals("-10.0000", cf.apply(cell).text); + + cell.setCellValue("abc"); + assertEquals("abc", cf.apply(cell).text); + + } + + public void testApplyFormatHasThreePartsFirstIsDateFirstTwoHaveCondition() { + + // Create a workbook, row and cell to test with + Workbook wb = new HSSFWorkbook(); + Sheet sheet = wb.createSheet(); + Row row = sheet.createRow(0); + Cell cell = row.createCell(0); + + CellFormat cf = CellFormat.getInstance("[>=100]0.00;[>=10]dd/mm/yyyy;0.0"); + + cell.setCellValue(100); + assertEquals("100.00", cf.apply(cell).text); + + cell.setCellValue(10); + assertEquals("10/01/1900", cf.apply(cell).text); + + cell.setCellValue(0); + assertEquals("0.0", cf.apply(cell).text); + + cell.setCellValue(-10); + assertEquals("-10.0", cf.apply(cell).text); + + cell.setCellValue("abc"); + assertEquals("abc", cf.apply(cell).text); + + } + + public void testApplyFormatHasTwoPartsFirstHasConditionSecondIsGeneral() { + + // Create a workbook, row and cell to test with + Workbook wb = new HSSFWorkbook(); + Sheet sheet = wb.createSheet(); + Row row = sheet.createRow(0); + Cell cell = row.createCell(0); + + CellFormat cf = CellFormat.getInstance("[>=100]0.00;General"); + + cell.setCellValue(100); + assertEquals("100.00", cf.apply(cell).text); + + cell.setCellValue(10); + assertEquals("10", cf.apply(cell).text); + + cell.setCellValue(0); + assertEquals("0", cf.apply(cell).text); + + cell.setCellValue(-10); + assertEquals("-10", cf.apply(cell).text); + + cell.setCellValue("abc"); + assertEquals("abc", cf.apply(cell).text); + + } + + public void testApplyFormatHasThreePartsFirstTwoHaveConditionThirdIsGeneral() { + + // Create a workbook, row and cell to test with + Workbook wb = new HSSFWorkbook(); + Sheet sheet = wb.createSheet(); + Row row = sheet.createRow(0); + Cell cell = row.createCell(0); + + CellFormat cf = CellFormat.getInstance("[>=100]0.00;[>=10]0.000;General"); + + cell.setCellValue(100); + assertEquals("100.00", cf.apply(cell).text); + + cell.setCellValue(10); + assertEquals("10.000", cf.apply(cell).text); + + cell.setCellValue(0); + assertEquals("0", cf.apply(cell).text); + + cell.setCellValue(-10); + assertEquals("-10", cf.apply(cell).text); + + cell.setCellValue("abc"); + assertEquals("abc", cf.apply(cell).text); + + } + + public void testApplyFormatHasFourPartsFirstHasCondition() { + + // Create a workbook, row and cell to test with + Workbook wb = new HSSFWorkbook(); + Sheet sheet = wb.createSheet(); + Row row = sheet.createRow(0); + Cell cell = row.createCell(0); + + CellFormat cf = CellFormat.getInstance("[>=100]0.00;0.000;0.0000;~~@~~"); + + cell.setCellValue(100); + assertEquals("100.00", cf.apply(cell).text); + + cell.setCellValue(10); + assertEquals("10.0000", cf.apply(cell).text); + + cell.setCellValue(0.123456789012345); + assertEquals("0.1235", cf.apply(cell).text); + + cell.setCellValue(0); + assertEquals("0.0000", cf.apply(cell).text); + + // Second format part ('0.000') is used for negative numbers + // so result does not have a minus sign + cell.setCellValue(-10); + assertEquals("10.000", cf.apply(cell).text); + + cell.setCellValue("abc"); + assertEquals("~~abc~~", cf.apply(cell).text); + + } + + public void testApplyFormatHasFourPartsSecondHasCondition() { + + // Create a workbook, row and cell to test with + Workbook wb = new HSSFWorkbook(); + Sheet sheet = wb.createSheet(); + Row row = sheet.createRow(0); + Cell cell = row.createCell(0); + + CellFormat cf = CellFormat.getInstance("0.00;[>=100]0.000;0.0000;~~@~~"); + + cell.setCellValue(100); + assertEquals("100.00", cf.apply(cell).text); + + cell.setCellValue(10); + assertEquals("10.00", cf.apply(cell).text); + + cell.setCellValue(0.123456789012345); + assertEquals("0.12", cf.apply(cell).text); + + cell.setCellValue(0); + assertEquals("0.0000", cf.apply(cell).text); + + cell.setCellValue(-10); + assertEquals("-10.0000", cf.apply(cell).text); + + cell.setCellValue("abc"); + assertEquals("~~abc~~", cf.apply(cell).text); + + cell.setCellValue(true); + assertEquals("~~TRUE~~", cf.apply(cell).text); + + } + + public void testApplyFormatHasFourPartsFirstTwoHaveCondition() { + + // Create a workbook, row and cell to test with + Workbook wb = new HSSFWorkbook(); + Sheet sheet = wb.createSheet(); + Row row = sheet.createRow(0); + Cell cell = row.createCell(0); + + CellFormat cf = CellFormat.getInstance("[>=100]0.00;[>=10]0.000;0.0000;~~@~~"); + + cell.setCellValue(100); + assertEquals("100.00", cf.apply(cell).text); + + cell.setCellValue(10); + assertEquals("10.000", cf.apply(cell).text); + + cell.setCellValue(0); + assertEquals("0.0000", cf.apply(cell).text); + + cell.setCellValue(-10); + assertEquals("-10.0000", cf.apply(cell).text); + + cell.setCellValue("abc"); + assertEquals("~~abc~~", cf.apply(cell).text); + + cell.setCellValue(true); + assertEquals("~~TRUE~~", cf.apply(cell).text); + } + + /* + * Test apply(Object value) with a number as parameter + */ + public void testApplyObjectNumber() { + + CellFormat cf1 = CellFormat.getInstance("0.000"); + + assertEquals("1.235", cf1.apply(1.2345).text); + assertEquals("-1.235", cf1.apply(-1.2345).text); + + CellFormat cf2 = CellFormat.getInstance("0.000;(0.000)"); + + assertEquals("1.235", cf2.apply(1.2345).text); + assertEquals("(1.235)", cf2.apply(-1.2345).text); + + CellFormat cf3 = CellFormat.getInstance("[>1]0.000;0.0000"); + + assertEquals("1.235", cf3.apply(1.2345).text); + assertEquals("-1.2345", cf3.apply(-1.2345).text); + + CellFormat cf4 = CellFormat.getInstance("0.000;[>1]0.0000"); + + assertEquals("1.235", cf4.apply(1.2345).text); + assertEquals(_255_POUND_SIGNS, cf4.apply(-1.2345).text); + + } + + /* + * Test apply(Object value) with a Date as parameter + */ + public void testApplyObjectDate() throws ParseException { + + CellFormat cf1 = CellFormat.getInstance("m/d/yyyy"); + Date date1 = new SimpleDateFormat("M/d/y").parse("01/11/2012"); + assertEquals("1/11/2012", cf1.apply(date1).text); + + } + + public void testApplyCellForDateFormatWithConditions() { + + // Create a workbook, row and cell to test with + Workbook wb = new HSSFWorkbook(); + Sheet sheet = wb.createSheet(); + Row row = sheet.createRow(0); + Cell cell = row.createCell(0); + + CellFormat cf = CellFormat.getInstance("[<1]hh:mm:ss AM/PM;[>=1]dd/mm/yyyy hh:mm:ss AM/PM;General"); + + cell.setCellValue(0.5); + assertEquals("12:00:00 PM", cf.apply(cell).text); + + cell.setCellValue(1.5); + assertEquals("01/01/1900 12:00:00 PM", cf.apply(cell).text); + + cell.setCellValue(-1); + assertEquals(_255_POUND_SIGNS, cf.apply(cell).text); + + } + + /* + * Test apply(Object value) with a String as parameter + */ + public void testApplyObjectString() { + + CellFormat cf = CellFormat.getInstance("0.00"); + + assertEquals("abc", cf.apply("abc").text); + + } + + /* + * Test apply(Object value) with a Boolean as parameter + */ + public void testApplyObjectBoolean() { + + CellFormat cf1 = CellFormat.getInstance("0"); + CellFormat cf2 = CellFormat.getInstance("General"); + CellFormat cf3 = CellFormat.getInstance("@"); + + assertEquals("TRUE", cf1.apply(true).text); + assertEquals("FALSE", cf2.apply(false).text); + assertEquals("TRUE", cf3.apply(true).text); + + } + } \ No newline at end of file