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