    001    /* ===========================================================
    002     * JFreeChart : a free chart library for the Java(tm) platform
    003     * ===========================================================
    004     *
    005     * (C) Copyright 2000-2007, 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     * DateTickUnit.java
    029     * -----------------
    030     * (C) Copyright 2000-2007, by Object Refinery Limited.
    031     *
    032     * Original Author:  David Gilbert (for Object Refinery Limited);
    033     * Contributor(s):   -;
    034     *
    035     * $Id: DateTickUnit.java,v 1.7.2.2 2007/03/21 10:07:47 mungady Exp $
    036     *
    037     * Changes (from 8-Nov-2002)
    038     * --------------------------
    039     * 08-Nov-2002 : Moved to new package com.jrefinery.chart.axis (DG);
    040     * 27-Nov-2002 : Added IllegalArgumentException to getMillisecondCount()
    041     *               method (DG);
    042     * 26-Mar-2003 : Implemented Serializable (DG);
    043     * 12-Nov-2003 : Added roll fields that can improve the labelling on segmented
    044     *               date axes (DG);
    045     * 03-Dec-2003 : DateFormat constructor argument is now filled with an default
    046     *               if null (TM);
    047     * 07-Dec-2003 : Fixed bug (null pointer exception) in constructor (DG);
    048     * ------------- JFREECHART 1.0.x ---------------------------------------------
    049     * 21-Mar-2007 : Added toString() for debugging (DG);
    050     *
    051     */
    052
    053    package org.jfree.chart.axis;
    054
    055    import java.io.Serializable;
    056    import java.text.DateFormat;
    057    import java.util.Calendar;
    058    import java.util.Date;
    059
    060    import org.jfree.util.ObjectUtilities;
    061
    062    /**
    063     * A tick unit for use by subclasses of {@link DateAxis}. Instances of this
    064     * class are immutable.
    065     */
    066    public class DateTickUnit extends TickUnit implements Serializable {
    067
    068        /** For serialization. */
    069        private static final long serialVersionUID = -7289292157229621901L;
    070
    071        /** A constant for years. */
    072        public static final int YEAR = 0;
    073
    074        /** A constant for months. */
    075        public static final int MONTH = 1;
    076
    077        /** A constant for days. */
    078        public static final int DAY = 2;
    079
    080        /** A constant for hours. */
    081        public static final int HOUR = 3;
    082
    083        /** A constant for minutes. */
    084        public static final int MINUTE = 4;
    085
    086        /** A constant for seconds. */
    087        public static final int SECOND = 5;
    088
    089        /** A constant for milliseconds. */
    090        public static final int MILLISECOND = 6;
    091
    092        /** The unit. */
    093        private int unit;
    094
    095        /** The unit count. */
    096        private int count;
    097
    098        /** The roll unit. */
    099        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    }