/* Copyright 2005-2006 Tim Fennell
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package net.sourceforge.stripes.format;
import net.sourceforge.stripes.exception.StripesRuntimeException;
import java.text.NumberFormat;
import java.text.DecimalFormat;
import java.util.HashSet;
import java.util.Locale;
import java.util.Set;
/**
* <p>Formats numbers into localized Strings for display. This class relies heavily on the
* NumberFormat and DecimalFormat classes in the java.text package, and it is suggested that you
* become familiar with those classes before using custom formats.</p>
*
* <p>Accepts the following named formatTypes (not case sensitive):</p>
* <ul>
* <li>number</li>
* <li>currency</li>
* <li>percentage</li>
* </ul>
*
* <p>If a format type is not supplied the default value of "number" will be used. Format String
* can be either a custom pattern as used by NumberFormat, or one of the following named formats
* (not case sensitive):</p>
* <ul>
* <li>plain - Outputs text in a manner similar to toString(), but appropriate to a locale.</li>
* <li>integer - Outputs text with grouping characters and no decimals.</li>
* <li>decimal - Outputs text with grouping characters and 2-6 decimal positions as needed.</li>
* </ul>
*
* @author Tim Fennell
*/
public class NumberFormatter implements Formatter<Number> {
/** Maintains a set of named formats that can be used instead of patterns. */
protected static final Set<String> namedPatterns = new HashSet<String>();
static {
namedPatterns.add("plain");
namedPatterns.add("integer");
namedPatterns.add("decimal");
}
private String formatType;
private String formatPattern;
private Locale locale;
private NumberFormat format;
/** Sets the format type to be used to render numbers as Strings. */
public void setFormatType(String formatType) {
this.formatType = formatType;
}
/** Gets the format type to be used to render numbers as Strings. */
public String getFormatType() {
return formatType;
}
/** Sets the named format string or number format pattern to use to format the number. */
public void setFormatPattern(String formatPattern) {
this.formatPattern = formatPattern;
}
/** Gets the named format string or number format pattern to use to format the number. */
public String getFormatPattern() {
return formatPattern;
}
/** Sets the locale that output String should be in. */
public void setLocale(Locale locale) {
this.locale = locale;
}
/** Gets the locale that output String should be in. */
public Locale getLocale() {
return locale;
}
/** Instantiates the NumberFormat based on the information provided through setter methods. */
public void init() {
// Set some sensible defaults if things are null
if (this.formatType == null) {
this.formatType = "number";
}
// Figure out which kind of number formatter to get
if (this.formatPattern == null) {
this.formatPattern = "plain";
}
if (this.formatType.equalsIgnoreCase("number")) {
this.format = NumberFormat.getInstance(locale);
}
else if (this.formatType.equalsIgnoreCase("currency")) {
this.format = NumberFormat.getCurrencyInstance(locale);
}
else if (this.formatType.equalsIgnoreCase("percentage")) {
this.format = NumberFormat.getPercentInstance(locale);
}
else {
throw new StripesRuntimeException("Invalid format type supplied for formatting a " +
"number: " + this.formatType + ". Valid values are 'number', 'currency' " +
"and 'percentage'.");
}
// Do any extra configuration
if (this.formatPattern.equalsIgnoreCase("plain")) {
this.format.setGroupingUsed(false);
}
else if (this.formatPattern.equalsIgnoreCase("integer")) {
this.format.setMaximumFractionDigits(0);
}
else if (this.formatPattern.equalsIgnoreCase(("decimal"))) {
this.format.setMinimumFractionDigits(2);
this.format.setMaximumFractionDigits(6);
}
else {
try {
((DecimalFormat) this.format).applyPattern(this.formatPattern);
}
catch (Exception e) {
throw new StripesRuntimeException("Custom pattern could not be applied to " +
"NumberFormat instance. Pattern was: " + this.formatPattern, e);
}
}
}
/** Formats the number supplied as a String. */
public String format(Number input) {
return this.format.format(input);
}
}