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
045package org.jfree.chart.axis;
046
047import java.awt.BasicStroke;
048import java.awt.Color;
049import java.awt.Font;
050import java.awt.Paint;
051import java.awt.Stroke;
052import java.io.IOException;
053import java.io.ObjectInputStream;
054import java.io.ObjectOutputStream;
055import java.io.Serializable;
056import java.lang.reflect.Constructor;
057import java.text.DateFormat;
058import java.util.Date;
059import java.util.TimeZone;
060
061import org.jfree.data.time.RegularTimePeriod;
062import org.jfree.io.SerialUtilities;
063import org.jfree.ui.RectangleInsets;
064
065/**
066 * A record that contains information for one "band" of date labels in 
067 * a {@link PeriodAxis}.
068 */
069public 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}