001    /* ===========================================================
002     * JFreeChart : a free chart library for the Java(tm) platform
003     * ===========================================================
004     *
005     * (C) Copyright 2000-2009, 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-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    }