    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    }