001: /*
002: * NumberColumnRenderer.java
003: *
004: * This file is part of SQL Workbench/J, http://www.sql-workbench.net
005: *
006: * Copyright 2002-2008, Thomas Kellerer
007: * No part of this code maybe reused without the permission of the author
008: *
009: * To contact the author please send an email to: support@sql-workbench.net
010: *
011: */
012: package workbench.gui.renderer;
013:
014: import java.math.BigDecimal;
015: import java.math.BigInteger;
016: import java.math.RoundingMode;
017: import java.text.DecimalFormat;
018: import java.text.DecimalFormatSymbols;
019: import java.util.concurrent.atomic.AtomicInteger;
020: import java.util.concurrent.atomic.AtomicInteger;
021: import java.util.concurrent.atomic.AtomicLong;
022: import javax.swing.SwingConstants;
023: import workbench.resource.Settings;
024:
025: /**
026: * @author support@sql-workbench.net
027: */
028: public class NumberColumnRenderer extends ToolTipRenderer {
029: private DecimalFormat decimalFormatter;
030: private DecimalFormatSymbols symb = new DecimalFormatSymbols();
031: private int maxDigits = -1;
032:
033: public NumberColumnRenderer() {
034: String sep = Settings.getInstance().getDecimalSymbol();
035: this .symb.setDecimalSeparator(sep.charAt(0));
036: decimalFormatter = new DecimalFormat("0.#", symb);
037: this .setMaxDigits(4);
038: this .setHorizontalAlignment(SwingConstants.RIGHT);
039: }
040:
041: public NumberColumnRenderer(int maxDigits) {
042: String sep = Settings.getInstance().getDecimalSymbol();
043: this .symb.setDecimalSeparator(sep.charAt(0));
044: decimalFormatter = new DecimalFormat("0.#", symb);
045: this .setMaxDigits(maxDigits);
046: this .setHorizontalAlignment(SwingConstants.RIGHT);
047: }
048:
049: public NumberColumnRenderer(int maxDigits, char sep) {
050: this .symb.setDecimalSeparator(sep);
051: decimalFormatter = new DecimalFormat("0.#", symb);
052: this .setMaxDigits(maxDigits);
053: this .setHorizontalAlignment(SwingConstants.RIGHT);
054: }
055:
056: public final void setMaxDigits(int digits) {
057: synchronized (this .decimalFormatter) {
058: if (digits <= 0)
059: this .maxDigits = 10;
060: else
061: this .maxDigits = digits;
062: decimalFormatter.setMaximumFractionDigits(maxDigits);
063: }
064: }
065:
066: public void setDecimalSymbol(char aSymbol) {
067: synchronized (this .decimalFormatter) {
068: this .symb.setDecimalSeparator(aSymbol);
069: this .decimalFormatter.setDecimalFormatSymbols(this .symb);
070: }
071: }
072:
073: private boolean isInteger(Number n) {
074: return (n instanceof Integer || n instanceof Long
075: || n instanceof Short || n instanceof BigInteger
076: || n instanceof AtomicInteger || n instanceof AtomicLong);
077: }
078:
079: public void prepareDisplay(Object aValue) {
080: try {
081: Number n = (Number) aValue;
082:
083: // BigDecimal cannot be formatted using a DecimalFormatter
084: // without possible loss of precission
085: if (n instanceof BigDecimal) {
086: BigDecimal d = (BigDecimal) n;
087:
088: // Oracle returns all numeric values as BigDecimal
089: // but if the value is actual an "Integer" toString() will
090: // return a String without a decimal separator
091: // in that case we won't apply the rounding to the
092: // required number of decimal digits
093: String v = d.toString();
094: if (v.lastIndexOf('.') > -1) {
095: char sepChar = this .symb.getDecimalSeparator();
096: // if a decimal point was found, then we have to apply rounding rules
097: BigDecimal rounded = d.setScale(this .maxDigits,
098: RoundingMode.HALF_UP);
099:
100: v = rounded.toString();
101: // toString() will use a dot as the decimal separator
102: // if the user configured a different one, we have to
103: // replace the last dot in the string with the user
104: // defined decimal separator.
105: if (sepChar != '.') {
106: int pos = v.lastIndexOf('.');
107: if (pos > -1) {
108: char[] ca = v.toCharArray();
109: ca[pos] = sepChar;
110: v = new String(ca);
111: }
112: }
113: }
114:
115: this .displayValue = v;
116: } else if (isInteger(n)) {
117: // BigInteger cannot be formatted without a possible
118: // loss of precission as well, but for "Integer" types,
119: // toString() should produce the correct results
120: displayValue = n.toString();
121: } else {
122: synchronized (this .decimalFormatter) {
123: displayValue = decimalFormatter.format(n
124: .doubleValue());
125: }
126: }
127: this .tooltip = aValue.toString();
128: } catch (Throwable th) {
129: displayValue = aValue.toString();
130: this.tooltip = null;
131: }
132: }
133: }
|