    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    }