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