    001    /* ===========================================================
    002     * JFreeChart : a free chart library for the Java(tm) platform
    003     * ===========================================================
    004     *
    005     * (C) Copyright 2000-2005, 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     * AbstractCategoryItemLabelGenerator.java
    029     * ---------------------------------------
    030     * (C) Copyright 2005, by Object Refinery Limited.
    031     *
    032     * Original Author:  David Gilbert (for Object Refinery Limited);
    033     * Contributor(s):   -;
    034     *
    035     * $Id: AbstractCategoryItemLabelGenerator.java,v 1.6.2.1 2005/10/25 20:49:02 mungady Exp $
    036     *
    037     * Changes
    038     * -------
    039     * 11-May-2004 : Version 1, distilled from StandardCategoryLabelGenerator (DG);
    040     * 31-Jan-2005 : Added methods to return row and column labels (DG);
    041     * 17-May-2005 : Added percentage to item array (DG);
    042     *
    043     */
    044
    045    package org.jfree.chart.labels;
    046
    047    import java.io.Serializable;
    048    import java.text.DateFormat;
    049    import java.text.MessageFormat;
    050    import java.text.NumberFormat;
    051
    052    import org.jfree.data.DataUtilities;
    053    import org.jfree.data.category.CategoryDataset;
    054    import org.jfree.util.ObjectUtilities;
    055    import org.jfree.util.PublicCloneable;
    056
    057    /**
    058     * A base class that can be used to create a label or tooltip generator that
    059     * can be assigned to a
    060     * {@link org.jfree.chart.renderer.category.CategoryItemRenderer}.
    061     */
    062    public abstract class AbstractCategoryItemLabelGenerator
    063                    implements PublicCloneable, Cloneable, Serializable {
    064
    065        /** For serialization. */
    066        private static final long serialVersionUID = -7108591260223293197L;
    067
    068        /**
    069         * The label format string used by a <code>MessageFormat</code> object to
    070         * combine the standard items:  {0} = series name, {1} = category,
    071         * {2} = value, {3} = value as a percentage of the column total.
    072         */
    073        private String labelFormat;
    074
    075        /** The string used to represent a null value. */
    076        private String nullValueString;
    077
    078        /**
    079         * A number formatter used to preformat the value before it is passed to
    080         * the MessageFormat object.
    081         */
    082        private NumberFormat numberFormat;
    083
    084        /**
    085         * A date formatter used to preformat the value before it is passed to the
    086         * MessageFormat object.
    087         */
    088        private DateFormat dateFormat;
    089
    090        /**
    091         * A number formatter used to preformat the percentage value before it is
    092         * passed to the MessageFormat object.
    093         */
    094        private NumberFormat percentFormat;
    095
    096        /**
    097         * Creates a label generator with the specified number formatter.
    098         *
    099         * @param labelFormat  the label format string (<code>null</code> not
    100         *                     permitted).
    101         * @param formatter  the number formatter (<code>null</code> not permitted).
    102         */
    103        protected AbstractCategoryItemLabelGenerator(String labelFormat,
    104                                                     NumberFormat formatter) {
    105            if (labelFormat == null) {
    106                throw new IllegalArgumentException("Null 'labelFormat' argument.");
    107            }
    108            if (formatter == null) {
    109                throw new IllegalArgumentException("Null 'formatter' argument.");
    110            }
    111            this.labelFormat = labelFormat;
    112            this.numberFormat = formatter;
    113            this.percentFormat = NumberFormat.getPercentInstance();
    114            this.dateFormat = null;
    115            this.nullValueString = "-";
    116        }
    117
    118        /**
    119         * Creates a label generator with the specified date formatter.
    120         *
    121         * @param labelFormat  the label format string (<code>null</code> not
    122         *                     permitted).
    123         * @param formatter  the date formatter (<code>null</code> not permitted).
    124         */
    125        protected AbstractCategoryItemLabelGenerator(String labelFormat,
    126                                                     DateFormat formatter) {
    127            if (labelFormat == null) {
    128                throw new IllegalArgumentException("Null 'labelFormat' argument.");
    129            }
    130            if (formatter == null) {
    131                throw new IllegalArgumentException("Null 'formatter' argument.");
    132            }
    133            this.labelFormat = labelFormat;
    134            this.numberFormat = null;
    135            this.percentFormat = NumberFormat.getPercentInstance();
    136            this.dateFormat = formatter;
    137            this.nullValueString = "-";
    138        }
    139
    140        /**
    141         * Generates a label for the specified row.
    142         *
    143         * @param dataset  the dataset (<code>null</code> not permitted).
    144         * @param row  the row index (zero-based).
    145         *
    146         * @return The label.
    147         */
    148        public String generateRowLabel(CategoryDataset dataset, int row) {
    149            return dataset.getRowKey(row).toString();
    150        }
    151
    152        /**
    153         * Generates a label for the specified row.
    154         *
    155         * @param dataset  the dataset (<code>null</code> not permitted).
    156         * @param column  the column index (zero-based).
    157         *
    158         * @return The label.
    159         */
    160        public String generateColumnLabel(CategoryDataset dataset, int column) {
    161            return dataset.getColumnKey(column).toString();
    162        }
    163
    164        /**
    165         * Returns the label format string.
    166         *
    167         * @return The label format string (never <code>null</code>).
    168         */
    169        public String getLabelFormat() {
    170            return this.labelFormat;
    171        }
    172
    173        /**
    174         * Returns the number formatter.
    175         *
    176         * @return The number formatter (possibly <code>null</code>).
    177         */
    178        public NumberFormat getNumberFormat() {
    179            return this.numberFormat;
    180        }
    181
    182        /**
    183         * Returns the date formatter.
    184         *
    185         * @return The date formatter (possibly <code>null</code>).
    186         */
    187        public DateFormat getDateFormat() {
    188            return this.dateFormat;
    189        }
    190
    191        /**
    192         * Generates a for the specified item.
    193         *
    194         * @param dataset  the dataset (<code>null</code> not permitted).
    195         * @param row  the row index (zero-based).
    196         * @param column  the column index (zero-based).
    197         *
    198         * @return The label (possibly <code>null</code>).
    199         */
    200        protected String generateLabelString(CategoryDataset dataset,
    201                                             int row, int column) {
    202            if (dataset == null) {
    203                throw new IllegalArgumentException("Null 'dataset' argument.");
    204            }
    205            String result = null;
    206            Object[] items = createItemArray(dataset, row, column);
    207            result = MessageFormat.format(this.labelFormat, items);
    208            return result;
    209
    210        }
    211
    212        /**
    213         * Creates the array of items that can be passed to the
    214         * {@link MessageFormat} class for creating labels.
    215         *
    216         * @param dataset  the dataset (<code>null</code> not permitted).
    217         * @param row  the row index (zero-based).
    218         * @param column  the column index (zero-based).
    219         *
    220         * @return The items (never <code>null</code>).
    221         */
    222        protected Object[] createItemArray(CategoryDataset dataset,
    223                                           int row, int column) {
    224            Object[] result = new Object[4];
    225            result[0] = dataset.getRowKey(row).toString();
    226            result[1] = dataset.getColumnKey(column).toString();
    227            Number value = dataset.getValue(row, column);
    228            if (value != null) {
    229                if (this.numberFormat != null) {
    230                    result[2] = this.numberFormat.format(value);
    231                }
    232                else if (this.dateFormat != null) {
    233                    result[2] = this.dateFormat.format(value);
    234                }
    235            }
    236            else {
    237                result[2] = this.nullValueString;
    238            }
    239            if (value != null) {
    240                double total = DataUtilities.calculateColumnTotal(dataset, column);
    241                double percent = value.doubleValue() / total;
    242                result[3] = this.percentFormat.format(percent);
    243            }
    244
    245            return result;
    246        }
    247
    248        /**
    249         * Tests this object for equality with an arbitrary object.
    250         *
    251         * @param obj  the other object (<code>null</code> permitted).
    252         *
    253         * @return A boolean.
    254         */
    255        public boolean equals(Object obj) {
    256            if (obj == this) {
    257                return true;
    258            }
    259            if (!(obj instanceof AbstractCategoryItemLabelGenerator)) {
    260                return false;
    261            }
    262
    263            AbstractCategoryItemLabelGenerator that
    264                = (AbstractCategoryItemLabelGenerator) obj;
    265            if (!this.labelFormat.equals(that.labelFormat)) {
    266                return false;
    267            }
    268            if (!ObjectUtilities.equal(this.dateFormat, that.dateFormat)) {
    269                return false;
    270            }
    271            if (!ObjectUtilities.equal(this.numberFormat, that.numberFormat)) {
    272                return false;
    273            }
    274            return true;
    275        }
    276
    277        /**
    278         * Returns an independent copy of the generator.
    279         *
    280         * @return A clone.
    281         *
    282         * @throws CloneNotSupportedException  should not happen.
    283         */
    284        public Object clone() throws CloneNotSupportedException {
    285            AbstractCategoryItemLabelGenerator clone
    286                = (AbstractCategoryItemLabelGenerator) super.clone();
    287            if (this.numberFormat != null) {
    288                clone.numberFormat = (NumberFormat) this.numberFormat.clone();
    289            }
    290            if (this.dateFormat != null) {
    291                clone.dateFormat = (DateFormat) this.dateFormat.clone();
    292            }
    293            return clone;
    294        }
    295
    296    }