001    /* ===========================================================
002     * JFreeChart : a free chart library for the Java(tm) platform
003     * ===========================================================
004     *
005     * (C) Copyright 2000-2008, 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, 2008, 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     * 
041     */
042    
043    package org.jfree.chart.util;
044    
045    import java.text.DecimalFormat;
046    import java.text.FieldPosition;
047    import java.text.NumberFormat;
048    import java.text.ParsePosition;
049    
050    /**
051     * A number formatter for logarithmic values.  This formatter does not support
052     * parsing.
053     * 
054     * @since 1.0.7
055     */
056    public class LogFormat extends NumberFormat {
057        
058        /** The log base value. */
059        private double base;
060        
061        /** The natural logarithm of the base value. */
062        private double baseLog;
063        
064        /** The label for the log base (for example, "e"). */
065        private String baseLabel;
066        
067        /** 
068         * The label for the power symbol.
069         * 
070         * @since 1.0.10
071         */
072        private String powerLabel;
073        
074        /** A flag that controls whether or not the base is shown. */
075        private boolean showBase;
076        
077        /** The number formatter for the exponent. */
078        private NumberFormat formatter = new DecimalFormat("0.0");
079        
080        /**
081         * Creates a new instance.
082         * 
083         * @param base  the base.
084         * @param baseLabel  the base label (<code>null</code> not permitted).
085         * @param showBase  a flag that controls whether or not the base value is
086         *                  shown.
087         */
088        public LogFormat(double base, String baseLabel, boolean showBase) {
089            this(base, baseLabel, "^", showBase);
090        }
091        
092        /**
093         * Creates a new instance.
094         * 
095         * @param base  the base.
096         * @param baseLabel  the base label (<code>null</code> not permitted).
097         * @param powerLabel  the power label (<code>null</code> not permitted).
098         * @param showBase  a flag that controls whether or not the base value is
099         *                  shown.
100         *                  
101         * @since 1.0.10
102         */
103        public LogFormat(double base, String baseLabel, String powerLabel, 
104                boolean showBase) {
105            if (baseLabel == null) {
106                throw new IllegalArgumentException("Null 'baseLabel' argument.");
107            }
108            if (powerLabel == null) {
109                throw new IllegalArgumentException("Null 'powerLabel' argument.");
110            }
111            this.base = base;
112            this.baseLog = Math.log(this.base);
113            this.baseLabel = baseLabel;
114            this.showBase = showBase;
115            this.powerLabel = powerLabel;
116        }
117    
118        /**
119         * Calculates the log of a given value.
120         * 
121         * @param value  the value.
122         * 
123         * @return The log of the value.
124         */
125        private double calculateLog(double value) {
126            return Math.log(value) / this.baseLog;
127        }
128        
129        /**
130         * Returns a formatted representation of the specified number.
131         * 
132         * @param number  the number.
133         * @param toAppendTo  the string buffer to append to.
134         * @param pos  the position.
135         * 
136         * @return A string buffer containing the formatted value.
137         */
138        public StringBuffer format(double number, StringBuffer toAppendTo,
139                FieldPosition pos) {
140            StringBuffer result = new StringBuffer();
141            if (this.showBase) {
142                result.append(this.baseLabel);
143                result.append(this.powerLabel);
144            }
145            result.append(this.formatter.format(calculateLog(number)));
146            return result;
147        }
148    
149        /**
150         * Formats the specified number as a hexadecimal string.  The decimal 
151         * fraction is ignored.
152         * 
153         * @param number  the number to format.
154         * @param toAppendTo  the buffer to append to (ignored here).
155         * @param pos  the field position (ignored here).
156         * 
157         * @return The string buffer.
158         */
159        public StringBuffer format(long number, StringBuffer toAppendTo, 
160                FieldPosition pos) {
161            StringBuffer result = new StringBuffer();
162            if (this.showBase) {
163                result.append(this.baseLabel);
164                result.append("^");
165            }
166            result.append(this.formatter.format(calculateLog(number)));
167            return result;
168        }
169    
170        /**
171         * Parsing is not implemented, so this method always returns 
172         * <code>null</code>.
173         * 
174         * @param source  ignored.
175         * @param parsePosition  ignored.
176         * 
177         * @return Always <code>null</code>.
178         */
179        public Number parse (String source, ParsePosition parsePosition) {
180            return null; // don't bother with parsing
181        }
182    
183        /**
184         * Tests this formatter for equality with an arbitrary object.
185         * 
186         * @param obj  the object (<code>null</code> permitted).
187         * 
188         * @return A boolean.
189         */
190        public boolean equals(Object obj) {
191            if (obj == this) {
192                return true;
193            }
194            if (!(obj instanceof LogFormat)) {
195                return false;
196            }
197            LogFormat that = (LogFormat) obj;
198            if (this.base != that.base) {
199                return false;
200            }
201            if (!this.baseLabel.equals(that.baseLabel)) {
202                return false;
203            }
204            if (this.baseLog != that.baseLog) {
205                return false;
206            }
207            if (this.showBase != that.showBase) {
208                return false;
209            }
210            return super.equals(obj);
211        }
212        
213        /**
214         * Returns a clone of this instance.
215         * 
216         * @return A clone.
217         */
218        public Object clone() {
219            LogFormat clone = (LogFormat) super.clone();
220            clone.formatter = (NumberFormat) this.formatter.clone();
221            return clone;
222        }
223    
224    }