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 }