Source for org.jfree.chart.axis.DateTickUnit

   1: /* ===========================================================
   2:  * JFreeChart : a free chart library for the Java(tm) platform
   3:  * ===========================================================
   4:  *
   5:  * (C) Copyright 2000-2005, by Object Refinery Limited and Contributors.
   6:  *
   7:  * Project Info:  http://www.jfree.org/jfreechart/index.html
   8:  *
   9:  * This library is free software; you can redistribute it and/or modify it 
  10:  * under the terms of the GNU Lesser General Public License as published by 
  11:  * the Free Software Foundation; either version 2.1 of the License, or 
  12:  * (at your option) any later version.
  13:  *
  14:  * This library is distributed in the hope that it will be useful, but 
  15:  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 
  16:  * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public 
  17:  * License for more details.
  18:  *
  19:  * You should have received a copy of the GNU Lesser General Public
  20:  * License along with this library; if not, write to the Free Software
  21:  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, 
  22:  * USA.  
  23:  *
  24:  * [Java is a trademark or registered trademark of Sun Microsystems, Inc. 
  25:  * in the United States and other countries.]
  26:  *
  27:  * -----------------
  28:  * DateTickUnit.java
  29:  * -----------------
  30:  * (C) Copyright 2000-2005, by Object Refinery Limited.
  31:  *
  32:  * Original Author:  David Gilbert (for Object Refinery Limited);
  33:  * Contributor(s):   -;
  34:  *
  35:  * $Id: DateTickUnit.java,v 1.7.2.1 2005/10/25 20:37:34 mungady Exp $
  36:  *
  37:  * Changes (from 8-Nov-2002)
  38:  * --------------------------
  39:  * 08-Nov-2002 : Moved to new package com.jrefinery.chart.axis (DG);
  40:  * 27-Nov-2002 : Added IllegalArgumentException to getMillisecondCount() 
  41:  *               method (DG);
  42:  * 26-Mar-2003 : Implemented Serializable (DG);
  43:  * 12-Nov-2003 : Added roll fields that can improve the labelling on segmented 
  44:  *               date axes (DG);
  45:  * 03-Dec-2003 : DateFormat constructor argument is now filled with an default 
  46:  *               if null (TM);
  47:  * 07-Dec-2003 : Fixed bug (null pointer exception) in constructor (DG);
  48:  *
  49:  */
  50: 
  51: package org.jfree.chart.axis;
  52: 
  53: import java.io.Serializable;
  54: import java.text.DateFormat;
  55: import java.util.Calendar;
  56: import java.util.Date;
  57: 
  58: import org.jfree.util.ObjectUtilities;
  59: 
  60: /**
  61:  * A tick unit for use by subclasses of {@link DateAxis}.
  62:  * <p>
  63:  * Instances of this class are immutable.
  64:  */
  65: public class DateTickUnit extends TickUnit implements Serializable {
  66: 
  67:     /** For serialization. */
  68:     private static final long serialVersionUID = -7289292157229621901L;
  69:     
  70:     /** A constant for years. */
  71:     public static final int YEAR = 0;
  72: 
  73:     /** A constant for months. */
  74:     public static final int MONTH = 1;
  75: 
  76:     /** A constant for days. */
  77:     public static final int DAY = 2;
  78: 
  79:     /** A constant for hours. */
  80:     public static final int HOUR = 3;
  81: 
  82:     /** A constant for minutes. */
  83:     public static final int MINUTE = 4;
  84: 
  85:     /** A constant for seconds. */
  86:     public static final int SECOND = 5;
  87: 
  88:     /** A constant for milliseconds. */
  89:     public static final int MILLISECOND = 6;
  90: 
  91:     /** The unit. */
  92:     private int unit;
  93: 
  94:     /** The unit count. */
  95:     private int count;
  96: 
  97:     /** The roll unit. */
  98:     private int rollUnit;
  99: 
 100:     /** The roll count. */
 101:     private int rollCount;
 102: 
 103:     /** The date formatter. */
 104:     private DateFormat formatter;
 105: 
 106:     /**
 107:      * Creates a new date tick unit.  The dates will be formatted using a 
 108:      * SHORT format for the default locale.
 109:      *
 110:      * @param unit  the unit.
 111:      * @param count  the unit count.
 112:      */
 113:     public DateTickUnit(int unit, int count) {
 114:         this(unit, count, null);
 115:     }
 116: 
 117:     /**
 118:      * Creates a new date tick unit.  You can specify the units using one of 
 119:      * the constants YEAR, MONTH, DAY, HOUR, MINUTE, SECOND or MILLISECOND.  
 120:      * In addition, you can specify a unit count, and a date format.
 121:      *
 122:      * @param unit  the unit.
 123:      * @param count  the unit count.
 124:      * @param formatter  the date formatter (defaults to DateFormat.SHORT).
 125:      */
 126:     public DateTickUnit(int unit, int count, DateFormat formatter) {
 127: 
 128:         this(unit, count, unit, count, formatter);
 129: 
 130:     }
 131: 
 132:     /**
 133:      * Creates a new unit.
 134:      *
 135:      * @param unit  the unit.
 136:      * @param count  the count.
 137:      * @param rollUnit  the roll unit.
 138:      * @param rollCount  the roll count.
 139:      * @param formatter  the date formatter (defaults to DateFormat.SHORT).
 140:      */
 141:     public DateTickUnit(int unit, int count, int rollUnit, int rollCount, 
 142:                         DateFormat formatter) {
 143:         super(DateTickUnit.getMillisecondCount(unit, count));
 144:         this.unit = unit;
 145:         this.count = count;
 146:         this.rollUnit = rollUnit;
 147:         this.rollCount = rollCount;
 148:         this.formatter = formatter;
 149:         if (formatter == null) {
 150:             this.formatter = DateFormat.getDateInstance(DateFormat.SHORT);
 151:         }
 152:     }
 153: 
 154:     /**
 155:      * Returns the date unit.  This will be one of the constants 
 156:      * <code>YEAR</code>, <code>MONTH</code>, <code>DAY</code>, 
 157:      * <code>HOUR</code>, <code>MINUTE</code>, <code>SECOND</code> or 
 158:      * <code>MILLISECOND</code>, defined by this class.  Note that these 
 159:      * constants do NOT correspond to those defined in Java's 
 160:      * <code>Calendar</code> class.
 161:      *
 162:      * @return The date unit.
 163:      */
 164:     public int getUnit() {
 165:         return this.unit;
 166:     }
 167: 
 168:     /**
 169:      * Returns the unit count.
 170:      *
 171:      * @return The unit count.
 172:      */
 173:     public int getCount() {
 174:         return this.count;
 175:     }
 176: 
 177:     /**
 178:      * Returns the roll unit.  This is the amount by which the tick advances if
 179:      * it is "hidden" when displayed on a segmented date axis.  Typically the 
 180:      * roll will be smaller than the regular tick unit (for example, a 7 day 
 181:      * tick unit might use a 1 day roll).
 182:      *
 183:      * @return The roll unit.
 184:      */
 185:     public int getRollUnit() {
 186:         return this.rollUnit;
 187:     }
 188: 
 189:     /**
 190:      * Returns the roll count.
 191:      *
 192:      * @return The roll count.
 193:      */
 194:     public int getRollCount() {
 195:         return this.rollCount;
 196:     }
 197: 
 198:     /**
 199:      * Formats a value.
 200:      *
 201:      * @param milliseconds  date in milliseconds since 01-01-1970.
 202:      *
 203:      * @return The formatted date.
 204:      */
 205:     public String valueToString(double milliseconds) {
 206:         return this.formatter.format(new Date((long) milliseconds));
 207:     }
 208: 
 209:     /**
 210:      * Formats a date using the tick unit's formatter.
 211:      *
 212:      * @param date  the date.
 213:      *
 214:      * @return The formatted date.
 215:      */
 216:     public String dateToString(Date date) {
 217:         return this.formatter.format(date);
 218:     }
 219: 
 220:     /**
 221:      * Calculates a new date by adding this unit to the base date.
 222:      *
 223:      * @param base  the base date.
 224:      *
 225:      * @return A new date one unit after the base date.
 226:      */
 227:     public Date addToDate(Date base) {
 228: 
 229:         Calendar calendar = Calendar.getInstance();
 230:         calendar.setTime(base);
 231:         calendar.add(getCalendarField(this.unit), this.count);
 232:         return calendar.getTime();
 233: 
 234:     }
 235: 
 236:     /**
 237:      * Rolls the date forward by the amount specified by the roll unit and 
 238:      * count.
 239:      *
 240:      * @param base  the base date.
 241: 
 242:      * @return The rolled date.
 243:      */
 244:     public Date rollDate(Date base) {
 245:         Calendar calendar = Calendar.getInstance();
 246:         calendar.setTime(base);
 247:         calendar.add(getCalendarField(this.rollUnit), this.rollCount);
 248:         return calendar.getTime();
 249:     }
 250: 
 251:     /**
 252:      * Returns a field code that can be used with the <code>Calendar</code> 
 253:      * class.
 254:      *
 255:      * @return The field code.
 256:      */
 257:     public int getCalendarField() {
 258:         return getCalendarField(this.unit);
 259:     }
 260: 
 261:     /**
 262:      * Returns a field code (that can be used with the Calendar class) for a 
 263:      * given 'unit' code.  The 'unit' is one of:  {@link #YEAR}, {@link #MONTH},
 264:      * {@link #DAY}, {@link #HOUR}, {@link #MINUTE}, {@link #SECOND} and 
 265:      * {@link #MILLISECOND}.
 266:      *
 267:      * @param tickUnit  the unit.
 268:      *
 269:      * @return The field code.
 270:      */
 271:     private int getCalendarField(int tickUnit) {
 272: 
 273:         switch (tickUnit) {
 274:             case (YEAR):
 275:                 return Calendar.YEAR;
 276:             case (MONTH):
 277:                 return Calendar.MONTH;
 278:             case (DAY):
 279:                 return Calendar.DATE;
 280:             case (HOUR):
 281:                 return Calendar.HOUR_OF_DAY;
 282:             case (MINUTE):
 283:                 return Calendar.MINUTE;
 284:             case (SECOND):
 285:                 return Calendar.SECOND;
 286:             case (MILLISECOND):
 287:                 return Calendar.MILLISECOND;
 288:             default:
 289:                 return Calendar.MILLISECOND;
 290:         }
 291: 
 292:     }
 293: 
 294:     /**
 295:      * Returns the (approximate) number of milliseconds for the given unit and 
 296:      * unit count.
 297:      * <P>
 298:      * This value is an approximation some of the time (e.g. months are 
 299:      * assumed to have 31 days) but this shouldn't matter.
 300:      *
 301:      * @param unit  the unit.
 302:      * @param count  the unit count.
 303:      *
 304:      * @return The number of milliseconds.
 305:      */
 306:     private static long getMillisecondCount(int unit, int count) {
 307: 
 308:         switch (unit) {
 309:             case (YEAR):
 310:                 return (365L * 24L * 60L * 60L * 1000L) * count;
 311:             case (MONTH):
 312:                 return (31L * 24L * 60L * 60L * 1000L) * count;
 313:             case (DAY):
 314:                 return (24L * 60L * 60L * 1000L) * count;
 315:             case (HOUR):
 316:                 return (60L * 60L * 1000L) * count;
 317:             case (MINUTE):
 318:                 return (60L * 1000L) * count;
 319:             case (SECOND):
 320:                 return 1000L * count;
 321:             case (MILLISECOND):
 322:                 return count;
 323:             default:
 324:                 throw new IllegalArgumentException(
 325:                     "DateTickUnit.getMillisecondCount() : unit must "
 326:                     + "be one of the constants YEAR, MONTH, DAY, HOUR, MINUTE, "
 327:                     + "SECOND or MILLISECOND defined in the DateTickUnit "
 328:                     + "class. Do *not* use the constants defined in "
 329:                     + "java.util.Calendar."
 330:                 );
 331:         }
 332: 
 333:     }
 334: 
 335:     /**
 336:      * Tests this unit for equality with another object.
 337:      *
 338:      * @param obj  the object (<code>null</code> permitted).
 339:      *
 340:      * @return <code>true</code> or <code>false</code>.
 341:      */
 342:     public boolean equals(Object obj) {
 343:         if (obj == this) {
 344:             return true;
 345:         }
 346:         if (!(obj instanceof DateTickUnit)) {
 347:             return false;
 348:         }
 349:         if (!super.equals(obj)) {
 350:             return false;
 351:         }
 352:         DateTickUnit that = (DateTickUnit) obj;
 353:         if (this.unit != that.unit) {
 354:             return false;
 355:         }
 356:         if (this.count != that.count) {
 357:             return false;
 358:         }
 359:         if (!ObjectUtilities.equal(this.formatter, that.formatter)) {
 360:             return false;
 361:         }
 362:         return true;
 363:     }
 364:     
 365:     /**
 366:      * Returns a hash code for this object.
 367:      * 
 368:      * @return A hash code.
 369:      */
 370:     public int hashCode() {
 371:         int result = 19;
 372:         result = 37 * result + this.unit;
 373:         result = 37 * result + this.count;
 374:         result = 37 * result + this.formatter.hashCode();
 375:         return result;
 376:     }
 377: 
 378: }