001    /* ===========================================================
002     * JFreeChart : a free chart library for the Java(tm) platform
003     * ===========================================================
004     *
005     * (C) Copyright 2000-2009, by Object Refinery Limited and Contributors.
006     *
007     * Project Info:  http://www.jfree.org/jfreechart/index.html
008     *
009     * This library is free software; you can redistribute it and/or modify it
010     * under the terms of the GNU Lesser General Public License as published by
011     * the Free Software Foundation; either version 2.1 of the License, or
012     * (at your option) any later version.
013     *
014     * This library is distributed in the hope that it will be useful, but
015     * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
016     * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
017     * License for more details.
018     *
019     * You should have received a copy of the GNU Lesser General Public
020     * License along with this library; if not, write to the Free Software
021     * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301,
022     * USA.
023     *
024     * [Java is a trademark or registered trademark of Sun Microsystems, Inc.
025     * in the United States and other countries.]
026     *
027     * --------------
028     * LogFormat.java
029     * --------------
030     * (C) Copyright 2007-2009, by Object Refinery Limited and Contributors.
031     *
032     * Original Author:  David Gilbert (for Object Refinery Limited);
033     * Contributor(s):   -;
034     *
035     * Changes
036     * -------
037     * 02-Aug-2007 : Version 1 (DG);
038     * 19-Feb-2008 : Implemented equals() and clone(), and added new powerLabel
039     *               attribute as per Feature Request 1886036 (DG);
040     * 14-Jan-2009 : Added default constructor, and accessor methods for
041     *               exponent formatter (DG);
042     *
043     */
044    
045    package org.jfree.chart.util;
046    
047    import java.text.DecimalFormat;
048    import java.text.FieldPosition;
049    import java.text.NumberFormat;
050    import java.text.ParsePosition;
051    
052    /**
053     * A number formatter for logarithmic values.  This formatter does not support
054     * parsing.
055     *
056     * @since 1.0.7
057     */
058    public class LogFormat extends NumberFormat {
059    
060        /** The log base value. */
061        private double base;
062    
063        /** The natural logarithm of the base value. */
064        private double baseLog;
065    
066        /** The label for the log base (for example, "e"). */
067        private String baseLabel;
068    
069        /**
070         * The label for the power symbol.
071         *
072         * @since 1.0.10
073         */
074        private String powerLabel;
075    
076        /** A flag that controls whether or not the base is shown. */
077        private boolean showBase;
078    
079        /** The number formatter for the exponent. */
080        private NumberFormat formatter = new DecimalFormat("0.0#");
081    
082        /**
083         * Creates a new instance using base 10.
084         *
085         * @since 1.0.13
086         */
087        public LogFormat() {
088            this(10.0, "10", true);
089        }
090    
091        /**
092         * Creates a new instance.
093         *
094         * @param base  the base.
095         * @param baseLabel  the base label (<code>null</code> not permitted).
096         * @param showBase  a flag that controls whether or not the base value is
097         *                  shown.
098         */
099        public LogFormat(double base, String baseLabel, boolean showBase) {
100            this(base, baseLabel, "^", showBase);
101        }
102    
103        /**
104         * Creates a new instance.
105         *
106         * @param base  the base.
107         * @param baseLabel  the base label (<code>null</code> not permitted).
108         * @param powerLabel  the power label (<code>null</code> not permitted).
109         * @param showBase  a flag that controls whether or not the base value is
110         *                  shown.
111         *
112         * @since 1.0.10
113         */
114        public LogFormat(double base, String baseLabel, String powerLabel,
115                boolean showBase) {
116            if (baseLabel == null) {
117                throw new IllegalArgumentException("Null 'baseLabel' argument.");
118            }
119            if (powerLabel == null) {
120                throw new IllegalArgumentException("Null 'powerLabel' argument.");
121            }
122            this.base = base;
123            this.baseLog = Math.log(this.base);
124            this.baseLabel = baseLabel;
125            this.showBase = showBase;
126            this.powerLabel = powerLabel;
127        }
128    
129        /**
130         * Returns the number format used for the exponent.
131         *
132         * @return The number format (never <code>null</code>).
133         *
134         * @since 1.0.13.
135         */
136        public NumberFormat getExponentFormat() {
137            return (NumberFormat) this.formatter.clone();
138        }
139    
140        /**
141         * Sets the number format used for the exponent.
142         *
143         * @param format  the formatter (<code>null</code> not permitted).
144         *
145         * @since 1.0.13
146         */
147        public void setExponentFormat(NumberFormat format) {
148            if (format == null) {
149                throw new IllegalArgumentException("Null 'format' argument.");
150            }
151            this.formatter = format;
152        }
153    
154        /**
155         * Calculates the log of a given value.
156         *
157         * @param value  the value.
158         *
159         * @return The log of the value.
160         */
161        private double calculateLog(double value) {
162            return Math.log(value) / this.baseLog;
163        }
164    
165        /**
166         * Returns a formatted representation of the specified number.
167         *
168         * @param number  the number.
169         * @param toAppendTo  the string buffer to append to.
170         * @param pos  the position.
171         *
172         * @return A string buffer containing the formatted value.
173         */
174        public StringBuffer format(double number, StringBuffer toAppendTo,
175                FieldPosition pos) {
176            StringBuffer result = new StringBuffer();
177            if (this.showBase) {
178                result.append(this.baseLabel);
179                result.append(this.powerLabel);
180            }
181            result.append(this.formatter.format(calculateLog(number)));
182            return result;
183        }
184    
185        /**
186         * Formats the specified number as a hexadecimal string.  The decimal
187         * fraction is ignored.
188         *
189         * @param number  the number to format.
190         * @param toAppendTo  the buffer to append to (ignored here).
191         * @param pos  the field position (ignored here).
192         *
193         * @return The string buffer.
194         */
195        public StringBuffer format(long number, StringBuffer toAppendTo,
196                FieldPosition pos) {
197            StringBuffer result = new StringBuffer();
198            if (this.showBase) {
199                result.append(this.baseLabel);
200                result.append("^");
201            }
202            result.append(this.formatter.format(calculateLog(number)));
203            return result;
204        }
205    
206        /**
207         * Parsing is not implemented, so this method always returns
208         * <code>null</code>.
209         *
210         * @param source  ignored.
211         * @param parsePosition  ignored.
212         *
213         * @return Always <code>null</code>.
214         */
215        public Number parse (String source, ParsePosition parsePosition) {
216            return null; // don't bother with parsing
217        }
218    
219        /**
220         * Tests this formatter for equality with an arbitrary object.
221         *
222         * @param obj  the object (<code>null</code> permitted).
223         *
224         * @return A boolean.
225         */
226        public boolean equals(Object obj) {
227            if (obj == this) {
228                return true;
229            }
230            if (!(obj instanceof LogFormat)) {
231                return false;
232            }
233            LogFormat that = (LogFormat) obj;
234            if (this.base != that.base) {
235                return false;
236            }
237            if (!this.baseLabel.equals(that.baseLabel)) {
238                return false;
239            }
240            if (this.baseLog != that.baseLog) {
241                return false;
242            }
243            if (this.showBase != that.showBase) {
244                return false;
245            }
246            if (!this.formatter.equals(that.formatter)) {
247                return false;
248            }
249            return super.equals(obj);
250        }
251    
252        /**
253         * Returns a clone of this instance.
254         *
255         * @return A clone.
256         */
257        public Object clone() {
258            LogFormat clone = (LogFormat) super.clone();
259            clone.formatter = (NumberFormat) this.formatter.clone();
260            return clone;
261        }
262    
263    }