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    }