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-2007, 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-2007, 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.2 2007/03/21 10:07:47 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:  * ------------- JFREECHART 1.0.x ---------------------------------------------
  49:  * 21-Mar-2007 : Added toString() for debugging (DG);
  50:  *
  51:  */
  52: 
  53: package org.jfree.chart.axis;
  54: 
  55: import java.io.Serializable;
  56: import java.text.DateFormat;
  57: import java.util.Calendar;
  58: import java.util.Date;
  59: 
  60: import org.jfree.util.ObjectUtilities;
  61: 
  62: /**
  63:  * A tick unit for use by subclasses of {@link DateAxis}. Instances of this 
  64:  * class are immutable.
  65:  */
  66: public class DateTickUnit extends TickUnit implements Serializable {
  67: 
  68:     /** For serialization. */
  69:     private static final long serialVersionUID = -7289292157229621901L;
  70:     
  71:     /** A constant for years. */
  72:     public static final int YEAR = 0;
  73: 
  74:     /** A constant for months. */
  75:     public static final int MONTH = 1;
  76: 
  77:     /** A constant for days. */
  78:     public static final int DAY = 2;
  79: 
  80:     /** A constant for hours. */
  81:     public static final int HOUR = 3;
  82: 
  83:     /** A constant for minutes. */
  84:     public static final int MINUTE = 4;
  85: 
  86:     /** A constant for seconds. */
  87:     public static final int SECOND = 5;
  88: 
  89:     /** A constant for milliseconds. */
  90:     public static final int MILLISECOND = 6;
  91: 
  92:     /** The unit. */
  93:     private int unit;
  94: 
  95:     /** The unit count. */
  96:     private int count;
  97: 
  98:     /** The roll unit. */
  99:     private int rollUnit;
 100: 
 101:     /** The roll count. */
 102:     private int rollCount;
 103: 
 104:     /** The date formatter. */
 105:     private DateFormat formatter;
 106: 
 107:     /**
 108:      * Creates a new date tick unit.  The dates will be formatted using a 
 109:      * SHORT format for the default locale.
 110:      *
 111:      * @param unit  the unit.
 112:      * @param count  the unit count.
 113:      */
 114:     public DateTickUnit(int unit, int count) {
 115:         this(unit, count, null);
 116:     }
 117: 
 118:     /**
 119:      * Creates a new date tick unit.  You can specify the units using one of 
 120:      * the constants YEAR, MONTH, DAY, HOUR, MINUTE, SECOND or MILLISECOND.  
 121:      * In addition, you can specify a unit count, and a date format.
 122:      *
 123:      * @param unit  the unit.
 124:      * @param count  the unit count.
 125:      * @param formatter  the date formatter (defaults to DateFormat.SHORT).
 126:      */
 127:     public DateTickUnit(int unit, int count, DateFormat formatter) {
 128: 
 129:         this(unit, count, unit, count, formatter);
 130: 
 131:     }
 132: 
 133:     /**
 134:      * Creates a new unit.
 135:      *
 136:      * @param unit  the unit.
 137:      * @param count  the count.
 138:      * @param rollUnit  the roll unit.
 139:      * @param rollCount  the roll count.
 140:      * @param formatter  the date formatter (defaults to DateFormat.SHORT).
 141:      */
 142:     public DateTickUnit(int unit, int count, int rollUnit, int rollCount, 
 143:                         DateFormat formatter) {
 144:         super(DateTickUnit.getMillisecondCount(unit, count));
 145:         this.unit = unit;
 146:         this.count = count;
 147:         this.rollUnit = rollUnit;
 148:         this.rollCount = rollCount;
 149:         this.formatter = formatter;
 150:         if (formatter == null) {
 151:             this.formatter = DateFormat.getDateInstance(DateFormat.SHORT);
 152:         }
 153:     }
 154: 
 155:     /**
 156:      * Returns the date unit.  This will be one of the constants 
 157:      * <code>YEAR</code>, <code>MONTH</code>, <code>DAY</code>, 
 158:      * <code>HOUR</code>, <code>MINUTE</code>, <code>SECOND</code> or 
 159:      * <code>MILLISECOND</code>, defined by this class.  Note that these 
 160:      * constants do NOT correspond to those defined in Java's 
 161:      * <code>Calendar</code> class.
 162:      *
 163:      * @return The date unit.
 164:      */
 165:     public int getUnit() {
 166:         return this.unit;
 167:     }
 168: 
 169:     /**
 170:      * Returns the unit count.
 171:      *
 172:      * @return The unit count.
 173:      */
 174:     public int getCount() {
 175:         return this.count;
 176:     }
 177: 
 178:     /**
 179:      * Returns the roll unit.  This is the amount by which the tick advances if
 180:      * it is "hidden" when displayed on a segmented date axis.  Typically the 
 181:      * roll will be smaller than the regular tick unit (for example, a 7 day 
 182:      * tick unit might use a 1 day roll).
 183:      *
 184:      * @return The roll unit.
 185:      */
 186:     public int getRollUnit() {
 187:         return this.rollUnit;
 188:     }
 189: 
 190:     /**
 191:      * Returns the roll count.
 192:      *
 193:      * @return The roll count.
 194:      */
 195:     public int getRollCount() {
 196:         return this.rollCount;
 197:     }
 198: 
 199:     /**
 200:      * Formats a value.
 201:      *
 202:      * @param milliseconds  date in milliseconds since 01-01-1970.
 203:      *
 204:      * @return The formatted date.
 205:      */
 206:     public String valueToString(double milliseconds) {
 207:         return this.formatter.format(new Date((long) milliseconds));
 208:     }
 209: 
 210:     /**
 211:      * Formats a date using the tick unit's formatter.
 212:      *
 213:      * @param date  the date.
 214:      *
 215:      * @return The formatted date.
 216:      */
 217:     public String dateToString(Date date) {
 218:         return this.formatter.format(date);
 219:     }
 220: 
 221:     /**
 222:      * Calculates a new date by adding this unit to the base date.
 223:      *
 224:      * @param base  the base date.
 225:      *
 226:      * @return A new date one unit after the base date.
 227:      */
 228:     public Date addToDate(Date base) {
 229: 
 230:         Calendar calendar = Calendar.getInstance();
 231:         calendar.setTime(base);
 232:         calendar.add(getCalendarField(this.unit), this.count);
 233:         return calendar.getTime();
 234: 
 235:     }
 236: 
 237:     /**
 238:      * Rolls the date forward by the amount specified by the roll unit and 
 239:      * count.
 240:      *
 241:      * @param base  the base date.
 242: 
 243:      * @return The rolled date.
 244:      */
 245:     public Date rollDate(Date base) {
 246:         Calendar calendar = Calendar.getInstance();
 247:         calendar.setTime(base);
 248:         calendar.add(getCalendarField(this.rollUnit), this.rollCount);
 249:         return calendar.getTime();
 250:     }
 251: 
 252:     /**
 253:      * Returns a field code that can be used with the <code>Calendar</code> 
 254:      * class.
 255:      *
 256:      * @return The field code.
 257:      */
 258:     public int getCalendarField() {
 259:         return getCalendarField(this.unit);
 260:     }
 261: 
 262:     /**
 263:      * Returns a field code (that can be used with the Calendar class) for a 
 264:      * given 'unit' code.  The 'unit' is one of:  {@link #YEAR}, {@link #MONTH},
 265:      * {@link #DAY}, {@link #HOUR}, {@link #MINUTE}, {@link #SECOND} and 
 266:      * {@link #MILLISECOND}.
 267:      *
 268:      * @param tickUnit  the unit.
 269:      *
 270:      * @return The field code.
 271:      */
 272:     private int getCalendarField(int tickUnit) {
 273: 
 274:         switch (tickUnit) {
 275:             case (YEAR):
 276:                 return Calendar.YEAR;
 277:             case (MONTH):
 278:                 return Calendar.MONTH;
 279:             case (DAY):
 280:                 return Calendar.DATE;
 281:             case (HOUR):
 282:                 return Calendar.HOUR_OF_DAY;
 283:             case (MINUTE):
 284:                 return Calendar.MINUTE;
 285:             case (SECOND):
 286:                 return Calendar.SECOND;
 287:             case (MILLISECOND):
 288:                 return Calendar.MILLISECOND;
 289:             default:
 290:                 return Calendar.MILLISECOND;
 291:         }
 292: 
 293:     }
 294: 
 295:     /**
 296:      * Returns the (approximate) number of milliseconds for the given unit and 
 297:      * unit count.
 298:      * <P>
 299:      * This value is an approximation some of the time (e.g. months are 
 300:      * assumed to have 31 days) but this shouldn't matter.
 301:      *
 302:      * @param unit  the unit.
 303:      * @param count  the unit count.
 304:      *
 305:      * @return The number of milliseconds.
 306:      */
 307:     private static long getMillisecondCount(int unit, int count) {
 308: 
 309:         switch (unit) {
 310:             case (YEAR):
 311:                 return (365L * 24L * 60L * 60L * 1000L) * count;
 312:             case (MONTH):
 313:                 return (31L * 24L * 60L * 60L * 1000L) * count;
 314:             case (DAY):
 315:                 return (24L * 60L * 60L * 1000L) * count;
 316:             case (HOUR):
 317:                 return (60L * 60L * 1000L) * count;
 318:             case (MINUTE):
 319:                 return (60L * 1000L) * count;
 320:             case (SECOND):
 321:                 return 1000L * count;
 322:             case (MILLISECOND):
 323:                 return count;
 324:             default:
 325:                 throw new IllegalArgumentException(
 326:                     "DateTickUnit.getMillisecondCount() : unit must "
 327:                     + "be one of the constants YEAR, MONTH, DAY, HOUR, MINUTE, "
 328:                     + "SECOND or MILLISECOND defined in the DateTickUnit "
 329:                     + "class. Do *not* use the constants defined in "
 330:                     + "java.util.Calendar."
 331:                 );
 332:         }
 333: 
 334:     }
 335: 
 336:     /**
 337:      * Tests this unit for equality with another object.
 338:      *
 339:      * @param obj  the object (<code>null</code> permitted).
 340:      *
 341:      * @return <code>true</code> or <code>false</code>.
 342:      */
 343:     public boolean equals(Object obj) {
 344:         if (obj == this) {
 345:             return true;
 346:         }
 347:         if (!(obj instanceof DateTickUnit)) {
 348:             return false;
 349:         }
 350:         if (!super.equals(obj)) {
 351:             return false;
 352:         }
 353:         DateTickUnit that = (DateTickUnit) obj;
 354:         if (this.unit != that.unit) {
 355:             return false;
 356:         }
 357:         if (this.count != that.count) {
 358:             return false;
 359:         }
 360:         if (!ObjectUtilities.equal(this.formatter, that.formatter)) {
 361:             return false;
 362:         }
 363:         return true;
 364:     }
 365:     
 366:     /**
 367:      * Returns a hash code for this object.
 368:      * 
 369:      * @return A hash code.
 370:      */
 371:     public int hashCode() {
 372:         int result = 19;
 373:         result = 37 * result + this.unit;
 374:         result = 37 * result + this.count;
 375:         result = 37 * result + this.formatter.hashCode();
 376:         return result;
 377:     }
 378:     
 379:     /**
 380:      * Strings for use by the toString() method.
 381:      */
 382:     private static final String[] units = {"YEAR", "MONTH", "DAY", "HOUR", 
 383:             "MINUTE", "SECOND", "MILLISECOND"};
 384:     
 385:     /**
 386:      * Returns a string representation of this instance, primarily used for
 387:      * debugging purposes.
 388:      *
 389:      * @return A string representation of this instance.
 390:      */
 391:     public String toString() {
 392:         return "DateTickUnit[" + DateTickUnit.units[this.unit] + ", " 
 393:                 + this.count + "]";
 394:     }
 395: 
 396: }