001    /* ===========================================================
002     * JFreeChart : a free chart library for the Java(tm) platform
003     * ===========================================================
004     *
005     * (C) Copyright 2000-2007, 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     * PeriodAxisLabelInfo.java
029     * ------------------------
030     * (C) Copyright 2004-2007, by Object Refinery Limited and Contributors.
031     *
032     * Original Author:  David Gilbert (for Object Refinery Limited);
033     * Contributor(s):   -;
034     *
035     * Changes
036     * -------
037     * 01-Jun-2004 : Version 1 (DG);
038     * 23-Feb-2005 : Replaced Spacer with RectangleInsets (DG);
039     * 01-Mar-2005 : Modified constructors to accept DateFormat (DG);
040     * 20-May-2005 : Added default constants and null argument checks in the 
041     *               constructor (DG);
042     * 
043     */
044    
045    package org.jfree.chart.axis;
046    
047    import java.awt.BasicStroke;
048    import java.awt.Color;
049    import java.awt.Font;
050    import java.awt.Paint;
051    import java.awt.Stroke;
052    import java.io.IOException;
053    import java.io.ObjectInputStream;
054    import java.io.ObjectOutputStream;
055    import java.io.Serializable;
056    import java.lang.reflect.Constructor;
057    import java.text.DateFormat;
058    import java.util.Date;
059    import java.util.TimeZone;
060    
061    import org.jfree.data.time.RegularTimePeriod;
062    import org.jfree.io.SerialUtilities;
063    import org.jfree.ui.RectangleInsets;
064    
065    /**
066     * A record that contains information for one "band" of date labels in 
067     * a {@link PeriodAxis}.
068     */
069    public class PeriodAxisLabelInfo implements Cloneable, Serializable {
070        
071        // TODO: this class is mostly immutable, so implementing Cloneable isn't
072        // really necessary.  But there is still a hole in that you can get the
073        // dateFormat and modify it.  We could return a copy, but that would slow
074        // things down. Needs resolving.
075        
076        /** For serialization. */
077        private static final long serialVersionUID = 5710451740920277357L;
078        
079        /** The default insets. */
080        public static final RectangleInsets DEFAULT_INSETS 
081            = new RectangleInsets(2, 2, 2, 2);
082        
083        /** The default font. */
084        public static final Font DEFAULT_FONT 
085            = new Font("SansSerif", Font.PLAIN, 10);
086        
087        /** The default label paint. */
088        public static final Paint DEFAULT_LABEL_PAINT = Color.black;
089        
090        /** The default divider stroke. */
091        public static final Stroke DEFAULT_DIVIDER_STROKE = new BasicStroke(0.5f);
092        
093        /** The default divider paint. */
094        public static final Paint DEFAULT_DIVIDER_PAINT = Color.gray;
095    
096        /** The subclass of {@link RegularTimePeriod} to use for this band. */
097        private Class periodClass;
098        
099        /** Controls the gaps around the band. */
100        private RectangleInsets padding;
101        
102        /** The date formatter. */
103        private DateFormat dateFormat;
104        
105        /** The label font. */
106        private Font labelFont;
107        
108        /** The label paint. */
109        private transient Paint labelPaint;
110        
111        /** A flag that controls whether or not dividers are visible. */
112        private boolean drawDividers;
113        
114        /** The stroke used to draw the dividers. */
115        private transient Stroke dividerStroke;
116        
117        /** The paint used to draw the dividers. */
118        private transient Paint dividerPaint;
119            
120        /**
121         * Creates a new instance.
122         * 
123         * @param periodClass  the subclass of {@link RegularTimePeriod} to use 
124         *                     (<code>null</code> not permitted).
125         * @param dateFormat  the date format (<code>null</code> not permitted).
126         */
127        public PeriodAxisLabelInfo(Class periodClass, DateFormat dateFormat) {
128            this(
129                periodClass, dateFormat, DEFAULT_INSETS, DEFAULT_FONT, 
130                DEFAULT_LABEL_PAINT, true, DEFAULT_DIVIDER_STROKE, 
131                DEFAULT_DIVIDER_PAINT
132            );
133        }
134        
135        /**
136         * Creates a new instance.
137         * 
138         * @param periodClass  the subclass of {@link RegularTimePeriod} to use
139         *                     (<code>null</code> not permitted).
140         * @param dateFormat  the date format (<code>null</code> not permitted).
141         * @param padding  controls the space around the band (<code>null</code> 
142         *                 not permitted).
143         * @param labelFont  the label font (<code>null</code> not permitted).
144         * @param labelPaint  the label paint (<code>null</code> not permitted).
145         * @param drawDividers  a flag that controls whether dividers are drawn.
146         * @param dividerStroke  the stroke used to draw the dividers 
147         *                       (<code>null</code> not permitted).
148         * @param dividerPaint  the paint used to draw the dividers 
149         *                      (<code>null</code> not permitted).
150         */
151        public PeriodAxisLabelInfo(Class periodClass, DateFormat dateFormat, 
152                                   RectangleInsets padding,
153                                   Font labelFont, Paint labelPaint, 
154                                   boolean drawDividers, Stroke dividerStroke, 
155                                   Paint dividerPaint) {
156            if (periodClass == null) {
157                throw new IllegalArgumentException("Null 'periodClass' argument.");
158            }
159            if (dateFormat == null) {
160                throw new IllegalArgumentException("Null 'dateFormat' argument.");
161            }
162            if (padding == null) {
163                throw new IllegalArgumentException("Null 'padding' argument.");
164            }
165            if (labelFont == null) {
166                throw new IllegalArgumentException("Null 'labelFont' argument.");
167            }
168            if (labelPaint == null) {
169                throw new IllegalArgumentException("Null 'labelPaint' argument.");
170            }
171            if (dividerStroke == null) {
172                throw new IllegalArgumentException(
173                        "Null 'dividerStroke' argument.");   
174            }
175            if (dividerPaint == null) {
176                throw new IllegalArgumentException("Null 'dividerPaint' argument.");
177            }
178            this.periodClass = periodClass;
179            this.dateFormat = dateFormat;
180            this.padding = padding;
181            this.labelFont = labelFont;
182            this.labelPaint = labelPaint;
183            this.drawDividers = drawDividers;
184            this.dividerStroke = dividerStroke;
185            this.dividerPaint = dividerPaint;
186        }
187        
188        /**
189         * Returns the subclass of {@link RegularTimePeriod} that should be used 
190         * to generate the date labels.
191         * 
192         * @return The class.
193         */
194        public Class getPeriodClass() {
195            return this.periodClass;   
196        }
197        
198        /**
199         * Returns the date formatter.
200         * 
201         * @return The date formatter (never <code>null</code>).
202         */
203        public DateFormat getDateFormat() {
204            return this.dateFormat;   
205        }
206        
207        /**
208         * Returns the padding for the band.
209         * 
210         * @return The padding.
211         */
212        public RectangleInsets getPadding() {
213            return this.padding;   
214        }
215        
216        /**
217         * Returns the label font.
218         * 
219         * @return The label font (never <code>null</code>).
220         */
221        public Font getLabelFont() {
222            return this.labelFont;   
223        }
224        
225        /**
226         * Returns the label paint.
227         * 
228         * @return The label paint.
229         */
230        public Paint getLabelPaint() {
231            return this.labelPaint;   
232        }
233        
234        /**
235         * Returns a flag that controls whether or not dividers are drawn.
236         * 
237         * @return A flag.
238         */
239        public boolean getDrawDividers() {
240            return this.drawDividers;   
241        }
242        
243        /**
244         * Returns the stroke used to draw the dividers.
245         * 
246         * @return The stroke.
247         */
248        public Stroke getDividerStroke() {
249            return this.dividerStroke;   
250        }
251        
252        /**
253         * Returns the paint used to draw the dividers.
254         * 
255         * @return The paint.
256         */
257        public Paint getDividerPaint() {
258            return this.dividerPaint;   
259        }
260        
261        /**
262         * Creates a time period that includes the specified millisecond, assuming
263         * the given time zone.
264         * 
265         * @param millisecond  the time.
266         * @param zone  the time zone.
267         * 
268         * @return The time period.
269         */
270        public RegularTimePeriod createInstance(Date millisecond, TimeZone zone) {
271            RegularTimePeriod result = null;
272            try {
273                Constructor c = this.periodClass.getDeclaredConstructor(
274                    new Class[] {Date.class, TimeZone.class}
275                );
276                result = (RegularTimePeriod) c.newInstance(
277                    new Object[] {millisecond, zone}
278                );   
279            }
280            catch (Exception e) {
281                // do nothing            
282            }
283            return result;  
284        }
285    
286        /**
287         * Tests this object for equality with an arbitrary object.
288         * 
289         * @param obj  the object to test against (<code>null</code> permitted).
290         * 
291         * @return A boolean.
292         */
293        public boolean equals(Object obj) {
294            if (obj == this) {
295                return true;   
296            }
297            if (obj instanceof PeriodAxisLabelInfo) {
298                PeriodAxisLabelInfo info = (PeriodAxisLabelInfo) obj;
299                if (!info.periodClass.equals(this.periodClass)) {
300                    return false;   
301                }
302                if (!info.dateFormat.equals(this.dateFormat)) {
303                    return false;   
304                }
305                if (!info.padding.equals(this.padding)) {
306                    return false;   
307                }
308                if (!info.labelFont.equals(this.labelFont)) {
309                    return false;
310                }
311                if (!info.labelPaint.equals(this.labelPaint)) {
312                    return false;   
313                }
314                if (info.drawDividers != this.drawDividers) {
315                    return false;   
316                }
317                if (!info.dividerStroke.equals(this.dividerStroke)) {
318                    return false;   
319                }
320                if (!info.dividerPaint.equals(this.dividerPaint)) {
321                    return false;   
322                }
323                return true;
324            }
325            return false;
326        }
327        
328        /**
329         * Returns a hash code for this object.
330         * 
331         * @return A hash code.
332         */
333        public int hashCode() {
334            int result = 41;
335            result = 37 * this.periodClass.hashCode();
336            result = 37 * this.dateFormat.hashCode();
337            return result;
338        }
339        
340        /**
341         * Returns a clone of the object.
342         * 
343         * @return A clone.
344         * 
345         * @throws CloneNotSupportedException if cloning is not supported.
346         */
347        public Object clone() throws CloneNotSupportedException {
348            PeriodAxisLabelInfo clone = (PeriodAxisLabelInfo) super.clone();
349            return clone;
350        }
351        
352        /**
353         * Provides serialization support.
354         *
355         * @param stream  the output stream.
356         *
357         * @throws IOException  if there is an I/O error.
358         */
359        private void writeObject(ObjectOutputStream stream) throws IOException {
360            stream.defaultWriteObject();
361            SerialUtilities.writePaint(this.labelPaint, stream);
362            SerialUtilities.writeStroke(this.dividerStroke, stream);
363            SerialUtilities.writePaint(this.dividerPaint, stream);
364        }
365    
366        /**
367         * Provides serialization support.
368         *
369         * @param stream  the input stream.
370         *
371         * @throws IOException  if there is an I/O error.
372         * @throws ClassNotFoundException  if there is a classpath problem.
373         */
374        private void readObject(ObjectInputStream stream) 
375            throws IOException, ClassNotFoundException {
376            stream.defaultReadObject();
377            this.labelPaint = SerialUtilities.readPaint(stream);
378            this.dividerStroke = SerialUtilities.readStroke(stream);
379            this.dividerPaint = SerialUtilities.readPaint(stream);
380        }
381       
382    }