Source Code Cross Referenced for DateAxis.java in  » Chart » jfreechart » org » jfree » chart » axis » Java Source Code / Java DocumentationJava Source Code and Java Documentation

Java Source Code / Java Documentation
1. 6.0 JDK Core
2. 6.0 JDK Modules
3. 6.0 JDK Modules com.sun
4. 6.0 JDK Modules com.sun.java
5. 6.0 JDK Modules sun
6. 6.0 JDK Platform
7. Ajax
8. Apache Harmony Java SE
9. Aspect oriented
10. Authentication Authorization
11. Blogger System
12. Build
13. Byte Code
14. Cache
15. Chart
16. Chat
17. Code Analyzer
18. Collaboration
19. Content Management System
20. Database Client
21. Database DBMS
22. Database JDBC Connection Pool
23. Database ORM
24. Development
25. EJB Server geronimo
26. EJB Server GlassFish
27. EJB Server JBoss 4.2.1
28. EJB Server resin 3.1.5
29. ERP CRM Financial
30. ESB
31. Forum
32. GIS
33. Graphic Library
34. Groupware
35. HTML Parser
36. IDE
37. IDE Eclipse
38. IDE Netbeans
39. Installer
40. Internationalization Localization
41. Inversion of Control
42. Issue Tracking
43. J2EE
44. JBoss
45. JMS
46. JMX
47. Library
48. Mail Clients
49. Net
50. Parser
51. PDF
52. Portal
53. Profiler
54. Project Management
55. Report
56. RSS RDF
57. Rule Engine
58. Science
59. Scripting
60. Search Engine
61. Security
62. Sevlet Container
63. Source Control
64. Swing Library
65. Template Engine
66. Test Coverage
67. Testing
68. UML
69. Web Crawler
70. Web Framework
71. Web Mail
72. Web Server
73. Web Services
74. Web Services apache cxf 2.0.1
75. Web Services AXIS2
76. Wiki Engine
77. Workflow Engines
78. XML
79. XML UI
Java
Java Tutorial
Java Open Source
Jar File Download
Java Articles
Java Products
Java by API
Photoshop Tutorials
Maya Tutorials
Flash Tutorials
3ds-Max Tutorials
Illustrator Tutorials
GIMP Tutorials
C# / C Sharp
C# / CSharp Tutorial
C# / CSharp Open Source
ASP.Net
ASP.NET Tutorial
JavaScript DHTML
JavaScript Tutorial
JavaScript Reference
HTML / CSS
HTML CSS Reference
C / ANSI-C
C Tutorial
C++
C++ Tutorial
Ruby
PHP
Python
Python Tutorial
Python Open Source
SQL Server / T-SQL
SQL Server / T-SQL Tutorial
Oracle PL / SQL
Oracle PL/SQL Tutorial
PostgreSQL
SQL / MySQL
MySQL Tutorial
VB.Net
VB.Net Tutorial
Flash / Flex / ActionScript
VBA / Excel / Access / Word
XML
XML Tutorial
Microsoft Office PowerPoint 2007 Tutorial
Microsoft Office Excel 2007 Tutorial
Microsoft Office Word 2007 Tutorial
Java Source Code / Java Documentation » Chart » jfreechart » org.jfree.chart.axis 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


0001:        /* ===========================================================
0002:         * JFreeChart : a free chart library for the Java(tm) platform
0003:         * ===========================================================
0004:         *
0005:         * (C) Copyright 2000-2007, by Object Refinery Limited and Contributors.
0006:         *
0007:         * Project Info:  http://www.jfree.org/jfreechart/index.html
0008:         *
0009:         * This library is free software; you can redistribute it and/or modify it 
0010:         * under the terms of the GNU Lesser General Public License as published by 
0011:         * the Free Software Foundation; either version 2.1 of the License, or 
0012:         * (at your option) any later version.
0013:         *
0014:         * This library is distributed in the hope that it will be useful, but 
0015:         * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 
0016:         * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public 
0017:         * License for more details.
0018:         *
0019:         * You should have received a copy of the GNU Lesser General Public
0020:         * License along with this library; if not, write to the Free Software
0021:         * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, 
0022:         * USA.  
0023:         *
0024:         * [Java is a trademark or registered trademark of Sun Microsystems, Inc. 
0025:         * in the United States and other countries.]
0026:         *
0027:         * -------------
0028:         * DateAxis.java
0029:         * -------------
0030:         * (C) Copyright 2000-2007, by Object Refinery Limited and Contributors.
0031:         *
0032:         * Original Author:  David Gilbert;
0033:         * Contributor(s):   Jonathan Nash;
0034:         *                   David Li;
0035:         *                   Michael Rauch;
0036:         *                   Bill Kelemen;
0037:         *                   Pawel Pabis;
0038:         *                   Chris Boek;
0039:         *
0040:         * $Id: DateAxis.java,v 1.17.2.11 2007/05/03 14:27:11 mungady Exp $
0041:         *
0042:         * Changes (from 23-Jun-2001)
0043:         * --------------------------
0044:         * 23-Jun-2001 : Modified to work with null data source (DG);
0045:         * 18-Sep-2001 : Updated header (DG);
0046:         * 27-Nov-2001 : Changed constructors from public to protected, updated Javadoc 
0047:         *               comments (DG);
0048:         * 16-Jan-2002 : Added an optional crosshair, based on the implementation by 
0049:         *               Jonathan Nash (DG);
0050:         * 26-Feb-2002 : Updated import statements (DG);
0051:         * 22-Apr-2002 : Added a setRange() method (DG);
0052:         * 25-Jun-2002 : Removed redundant local variable (DG);
0053:         * 25-Jul-2002 : Changed order of parameters in ValueAxis constructor (DG);
0054:         * 21-Aug-2002 : The setTickUnit() method now turns off auto-tick unit 
0055:         *               selection (fix for bug id 528885) (DG);
0056:         * 05-Sep-2002 : Updated the constructors to reflect changes in the Axis 
0057:         *               class (DG);
0058:         * 18-Sep-2002 : Fixed errors reported by Checkstyle (DG);
0059:         * 25-Sep-2002 : Added new setRange() methods, and deprecated 
0060:         *               setAxisRange() (DG);
0061:         * 04-Oct-2002 : Changed auto tick selection to parallel number axis 
0062:         *               classes (DG);
0063:         * 24-Oct-2002 : Added a date format override (DG);
0064:         * 08-Nov-2002 : Moved to new package com.jrefinery.chart.axis (DG);
0065:         * 14-Jan-2003 : Changed autoRangeMinimumSize from Number --> double, moved
0066:         *               crosshair settings to the plot (DG);
0067:         * 15-Jan-2003 : Removed anchor date (DG);
0068:         * 20-Jan-2003 : Removed unnecessary constructors (DG);
0069:         * 26-Mar-2003 : Implemented Serializable (DG);
0070:         * 02-May-2003 : Added additional units to createStandardDateTickUnits() 
0071:         *               method, as suggested by mhilpert in bug report 723187 (DG);
0072:         * 13-May-2003 : Merged HorizontalDateAxis and VerticalDateAxis (DG);
0073:         * 24-May-2003 : Added support for underlying timeline for 
0074:         *               SegmentedTimeline (BK);
0075:         * 16-Jul-2003 : Applied patch from Pawel Pabis to fix overlapping dates (DG);
0076:         * 22-Jul-2003 : Applied patch from Pawel Pabis for monthly ticks (DG);
0077:         * 25-Jul-2003 : Fixed bug 777561 and 777586 (DG);
0078:         * 13-Aug-2003 : Implemented Cloneable and added equals() method (DG);
0079:         * 02-Sep-2003 : Fixes for bug report 790506 (DG);
0080:         * 04-Sep-2003 : Fixed tick label alignment when axis appears at the top (DG);
0081:         * 10-Sep-2003 : Fixes for segmented timeline (DG);
0082:         * 17-Sep-2003 : Fixed a layout bug when multiple domain axes are used (DG);
0083:         * 29-Oct-2003 : Added workaround for font alignment in PDF output (DG);
0084:         * 07-Nov-2003 : Modified to use new tick classes (DG);
0085:         * 12-Nov-2003 : Modified tick labelling to use roll unit from DateTickUnit 
0086:         *               when a calculated tick value is hidden (which can occur in 
0087:         *               segmented date axes) (DG);
0088:         * 24-Nov-2003 : Fixed some problems with the auto tick unit selection, and 
0089:         *               fixed bug 846277 (labels missing for inverted axis) (DG);
0090:         * 30-Dec-2003 : Fixed bug in refreshTicksHorizontal() when start of time unit 
0091:         *               (ex. 1st of month) was hidden, causing infinite loop (BK);
0092:         * 13-Jan-2004 : Fixed bug in previousStandardDate() method (fix by Richard 
0093:         *               Wardle) (DG);
0094:         * 21-Jan-2004 : Renamed translateJava2DToValue --> java2DToValue, and 
0095:         *               translateValueToJava2D --> valueToJava2D (DG); 
0096:         * 12-Mar-2004 : Fixed bug where date format override is ignored for vertical 
0097:         *               axis (DG);
0098:         * 16-Mar-2004 : Added plotState to draw() method (DG);
0099:         * 07-Apr-2004 : Changed string width calculation (DG);
0100:         * 21-Apr-2004 : Fixed bug in estimateMaximumTickLabelWidth() method (bug id 
0101:         *               939148) (DG);
0102:         * 11-Jan-2005 : Removed deprecated methods in preparation for 1.0.0 
0103:         *               release (DG);
0104:         * 13-Jan-2005 : Fixed bug (see 
0105:         *               http://www.jfree.org/forum/viewtopic.php?t=11330) (DG);
0106:         * 21-Apr-2005 : Replaced Insets with RectangleInsets, removed redundant 
0107:         *               argument from selectAutoTickUnit() (DG);
0108:         * ------------- JFREECHART 1.0.x ---------------------------------------------
0109:         * 10-Feb-2006 : Added some API doc comments in respect of bug 821046 (DG);
0110:         * 19-Apr-2006 : Fixed bug 1472942 in equals() method (DG);
0111:         * 25-Sep-2006 : Fixed bug 1564977 missing tick labels (DG);
0112:         * 15-Jan-2007 : Added get/setTimeZone() suggested by 'skunk' (DG);
0113:         * 18-Jan-2007 : Fixed bug 1638678, time zone for calendar in 
0114:         *               previousStandardDate() (DG);
0115:         * 04-Apr-2007 : Use time zone in date calculations (CB);
0116:         * 19-Apr-2007 : Fix exceptions in setMinimum/MaximumDate() (DG);
0117:         * 03-May-2007 : Fixed minor bugs in previousStandardDate(), with new JUnit
0118:         *               tests (DG);
0119:         * 
0120:         */
0121:
0122:        package org.jfree.chart.axis;
0123:
0124:        import java.awt.Font;
0125:        import java.awt.FontMetrics;
0126:        import java.awt.Graphics2D;
0127:        import java.awt.font.FontRenderContext;
0128:        import java.awt.font.LineMetrics;
0129:        import java.awt.geom.Rectangle2D;
0130:        import java.io.Serializable;
0131:        import java.text.DateFormat;
0132:        import java.text.SimpleDateFormat;
0133:        import java.util.Calendar;
0134:        import java.util.Date;
0135:        import java.util.List;
0136:        import java.util.TimeZone;
0137:
0138:        import org.jfree.chart.event.AxisChangeEvent;
0139:        import org.jfree.chart.plot.Plot;
0140:        import org.jfree.chart.plot.PlotRenderingInfo;
0141:        import org.jfree.chart.plot.ValueAxisPlot;
0142:        import org.jfree.data.Range;
0143:        import org.jfree.data.time.DateRange;
0144:        import org.jfree.data.time.Month;
0145:        import org.jfree.data.time.RegularTimePeriod;
0146:        import org.jfree.data.time.Year;
0147:        import org.jfree.ui.RectangleEdge;
0148:        import org.jfree.ui.RectangleInsets;
0149:        import org.jfree.ui.TextAnchor;
0150:        import org.jfree.util.ObjectUtilities;
0151:
0152:        /**
0153:         * The base class for axes that display dates.  You will find it easier to 
0154:         * understand how this axis works if you bear in mind that it really 
0155:         * displays/measures integer (or long) data, where the integers are 
0156:         * milliseconds since midnight, 1-Jan-1970.  When displaying tick labels, the 
0157:         * millisecond values are converted back to dates using a 
0158:         * <code>DateFormat</code> instance.
0159:         * <P>
0160:         * You can also create a {@link org.jfree.chart.axis.Timeline} and supply in 
0161:         * the constructor to create an axis that only contains certain domain values. 
0162:         * For example, this allows you to create a date axis that only contains 
0163:         * working days.
0164:         */
0165:        public class DateAxis extends ValueAxis implements  Cloneable,
0166:                Serializable {
0167:
0168:            /** For serialization. */
0169:            private static final long serialVersionUID = -1013460999649007604L;
0170:
0171:            /** The default axis range. */
0172:            public static final DateRange DEFAULT_DATE_RANGE = new DateRange();
0173:
0174:            /** The default minimum auto range size. */
0175:            public static final double DEFAULT_AUTO_RANGE_MINIMUM_SIZE_IN_MILLISECONDS = 2.0;
0176:
0177:            /** The default date tick unit. */
0178:            public static final DateTickUnit DEFAULT_DATE_TICK_UNIT = new DateTickUnit(
0179:                    DateTickUnit.DAY, 1, new SimpleDateFormat());
0180:
0181:            /** The default anchor date. */
0182:            public static final Date DEFAULT_ANCHOR_DATE = new Date();
0183:
0184:            /** The current tick unit. */
0185:            private DateTickUnit tickUnit;
0186:
0187:            /** The override date format. */
0188:            private DateFormat dateFormatOverride;
0189:
0190:            /** 
0191:             * Tick marks can be displayed at the start or the middle of the time 
0192:             * period. 
0193:             */
0194:            private DateTickMarkPosition tickMarkPosition = DateTickMarkPosition.START;
0195:
0196:            /**
0197:             * A timeline that includes all milliseconds (as defined by 
0198:             * <code>java.util.Date</code>) in the real time line.
0199:             */
0200:            private static class DefaultTimeline implements  Timeline,
0201:                    Serializable {
0202:
0203:                /**
0204:                 * Converts a millisecond into a timeline value.
0205:                 *
0206:                 * @param millisecond  the millisecond.
0207:                 *
0208:                 * @return The timeline value.
0209:                 */
0210:                public long toTimelineValue(long millisecond) {
0211:                    return millisecond;
0212:                }
0213:
0214:                /**
0215:                 * Converts a date into a timeline value.
0216:                 *
0217:                 * @param date  the domain value.
0218:                 *
0219:                 * @return The timeline value.
0220:                 */
0221:                public long toTimelineValue(Date date) {
0222:                    return date.getTime();
0223:                }
0224:
0225:                /**
0226:                 * Converts a timeline value into a millisecond (as encoded by 
0227:                 * <code>java.util.Date</code>).
0228:                 *
0229:                 * @param value  the value.
0230:                 *
0231:                 * @return The millisecond.
0232:                 */
0233:                public long toMillisecond(long value) {
0234:                    return value;
0235:                }
0236:
0237:                /**
0238:                 * Returns <code>true</code> if the timeline includes the specified 
0239:                 * domain value.
0240:                 *
0241:                 * @param millisecond  the millisecond.
0242:                 *
0243:                 * @return <code>true</code>.
0244:                 */
0245:                public boolean containsDomainValue(long millisecond) {
0246:                    return true;
0247:                }
0248:
0249:                /**
0250:                 * Returns <code>true</code> if the timeline includes the specified 
0251:                 * domain value.
0252:                 *
0253:                 * @param date  the date.
0254:                 *
0255:                 * @return <code>true</code>.
0256:                 */
0257:                public boolean containsDomainValue(Date date) {
0258:                    return true;
0259:                }
0260:
0261:                /**
0262:                 * Returns <code>true</code> if the timeline includes the specified 
0263:                 * domain value range.
0264:                 *
0265:                 * @param from  the start value.
0266:                 * @param to  the end value.
0267:                 *
0268:                 * @return <code>true</code>.
0269:                 */
0270:                public boolean containsDomainRange(long from, long to) {
0271:                    return true;
0272:                }
0273:
0274:                /**
0275:                 * Returns <code>true</code> if the timeline includes the specified 
0276:                 * domain value range.
0277:                 *
0278:                 * @param from  the start date.
0279:                 * @param to  the end date.
0280:                 *
0281:                 * @return <code>true</code>.
0282:                 */
0283:                public boolean containsDomainRange(Date from, Date to) {
0284:                    return true;
0285:                }
0286:
0287:                /**
0288:                 * Tests an object for equality with this instance.
0289:                 *
0290:                 * @param object  the object.
0291:                 *
0292:                 * @return A boolean.
0293:                 */
0294:                public boolean equals(Object object) {
0295:                    if (object == null) {
0296:                        return false;
0297:                    }
0298:                    if (object == this ) {
0299:                        return true;
0300:                    }
0301:                    if (object instanceof  DefaultTimeline) {
0302:                        return true;
0303:                    }
0304:                    return false;
0305:                }
0306:            }
0307:
0308:            /** A static default timeline shared by all standard DateAxis */
0309:            private static final Timeline DEFAULT_TIMELINE = new DefaultTimeline();
0310:
0311:            /** The time zone for the axis. */
0312:            private TimeZone timeZone;
0313:
0314:            /** Our underlying timeline. */
0315:            private Timeline timeline;
0316:
0317:            /**
0318:             * Creates a date axis with no label.
0319:             */
0320:            public DateAxis() {
0321:                this (null);
0322:            }
0323:
0324:            /**
0325:             * Creates a date axis with the specified label.
0326:             *
0327:             * @param label  the axis label (<code>null</code> permitted).
0328:             */
0329:            public DateAxis(String label) {
0330:                this (label, TimeZone.getDefault());
0331:            }
0332:
0333:            /**
0334:             * Creates a date axis. A timeline is specified for the axis. This allows 
0335:             * special transformations to occur between a domain of values and the 
0336:             * values included in the axis.
0337:             *
0338:             * @see org.jfree.chart.axis.SegmentedTimeline
0339:             *
0340:             * @param label  the axis label (<code>null</code> permitted).
0341:             * @param zone  the time zone.
0342:             */
0343:            public DateAxis(String label, TimeZone zone) {
0344:                super (label, DateAxis.createStandardDateTickUnits(zone));
0345:                setTickUnit(DateAxis.DEFAULT_DATE_TICK_UNIT, false, false);
0346:                setAutoRangeMinimumSize(DEFAULT_AUTO_RANGE_MINIMUM_SIZE_IN_MILLISECONDS);
0347:                setRange(DEFAULT_DATE_RANGE, false, false);
0348:                this .dateFormatOverride = null;
0349:                this .timeZone = zone;
0350:                this .timeline = DEFAULT_TIMELINE;
0351:            }
0352:
0353:            /**
0354:             * Returns the time zone for the axis.
0355:             * 
0356:             * @return The time zone.
0357:             * 
0358:             * @since 1.0.4
0359:             * @see #setTimeZone(TimeZone)
0360:             */
0361:            public TimeZone getTimeZone() {
0362:                return this .timeZone;
0363:            }
0364:
0365:            /**
0366:             * Sets the time zone for the axis and sends an {@link AxisChangeEvent} to
0367:             * all registered listeners.
0368:             * 
0369:             * @param zone  the time zone (<code>null</code> not permitted).
0370:             * 
0371:             * @since 1.0.4
0372:             * @see #getTimeZone()
0373:             */
0374:            public void setTimeZone(TimeZone zone) {
0375:                if (!this .timeZone.equals(zone)) {
0376:                    this .timeZone = zone;
0377:                    setStandardTickUnits(createStandardDateTickUnits(zone));
0378:                    notifyListeners(new AxisChangeEvent(this ));
0379:                }
0380:            }
0381:
0382:            /**
0383:             * Returns the underlying timeline used by this axis.
0384:             *
0385:             * @return The timeline.
0386:             */
0387:            public Timeline getTimeline() {
0388:                return this .timeline;
0389:            }
0390:
0391:            /**
0392:             * Sets the underlying timeline to use for this axis.
0393:             * <P>
0394:             * If the timeline is changed, an {@link AxisChangeEvent} is sent to all
0395:             * registered listeners.
0396:             *
0397:             * @param timeline  the timeline.
0398:             */
0399:            public void setTimeline(Timeline timeline) {
0400:                if (this .timeline != timeline) {
0401:                    this .timeline = timeline;
0402:                    notifyListeners(new AxisChangeEvent(this ));
0403:                }
0404:            }
0405:
0406:            /**
0407:             * Returns the tick unit for the axis.
0408:             * <p>
0409:             * Note: if the <code>autoTickUnitSelection</code> flag is 
0410:             * <code>true</code> the tick unit may be changed while the axis is being 
0411:             * drawn, so in that case the return value from this method may be
0412:             * irrelevant if the method is called before the axis has been drawn.
0413:             *
0414:             * @return The tick unit (possibly <code>null</code>).
0415:             * 
0416:             * @see #setTickUnit(DateTickUnit)
0417:             * @see ValueAxis#isAutoTickUnitSelection()
0418:             */
0419:            public DateTickUnit getTickUnit() {
0420:                return this .tickUnit;
0421:            }
0422:
0423:            /**
0424:             * Sets the tick unit for the axis.  The auto-tick-unit-selection flag is 
0425:             * set to <code>false</code>, and registered listeners are notified that 
0426:             * the axis has been changed.
0427:             *
0428:             * @param unit  the tick unit.
0429:             * 
0430:             * @see #getTickUnit()
0431:             * @see #setTickUnit(DateTickUnit, boolean, boolean)
0432:             */
0433:            public void setTickUnit(DateTickUnit unit) {
0434:                setTickUnit(unit, true, true);
0435:            }
0436:
0437:            /**
0438:             * Sets the tick unit attribute.
0439:             *
0440:             * @param unit  the new tick unit.
0441:             * @param notify  notify registered listeners?
0442:             * @param turnOffAutoSelection  turn off auto selection?
0443:             * 
0444:             * @see #getTickUnit()
0445:             */
0446:            public void setTickUnit(DateTickUnit unit, boolean notify,
0447:                    boolean turnOffAutoSelection) {
0448:
0449:                this .tickUnit = unit;
0450:                if (turnOffAutoSelection) {
0451:                    setAutoTickUnitSelection(false, false);
0452:                }
0453:                if (notify) {
0454:                    notifyListeners(new AxisChangeEvent(this ));
0455:                }
0456:
0457:            }
0458:
0459:            /**
0460:             * Returns the date format override.  If this is non-null, then it will be
0461:             * used to format the dates on the axis.
0462:             *
0463:             * @return The formatter (possibly <code>null</code>).
0464:             */
0465:            public DateFormat getDateFormatOverride() {
0466:                return this .dateFormatOverride;
0467:            }
0468:
0469:            /**
0470:             * Sets the date format override.  If this is non-null, then it will be 
0471:             * used to format the dates on the axis.
0472:             *
0473:             * @param formatter  the date formatter (<code>null</code> permitted).
0474:             */
0475:            public void setDateFormatOverride(DateFormat formatter) {
0476:                this .dateFormatOverride = formatter;
0477:                notifyListeners(new AxisChangeEvent(this ));
0478:            }
0479:
0480:            /**
0481:             * Sets the upper and lower bounds for the axis and sends an 
0482:             * {@link AxisChangeEvent} to all registered listeners.  As a side-effect, 
0483:             * the auto-range flag is set to false.
0484:             *
0485:             * @param range  the new range (<code>null</code> not permitted).
0486:             */
0487:            public void setRange(Range range) {
0488:                setRange(range, true, true);
0489:            }
0490:
0491:            /**
0492:             * Sets the range for the axis, if requested, sends an 
0493:             * {@link AxisChangeEvent} to all registered listeners.  As a side-effect, 
0494:             * the auto-range flag is set to <code>false</code> (optional).
0495:             *
0496:             * @param range  the range (<code>null</code> not permitted).
0497:             * @param turnOffAutoRange  a flag that controls whether or not the auto 
0498:             *                          range is turned off.
0499:             * @param notify  a flag that controls whether or not listeners are 
0500:             *                notified.
0501:             */
0502:            public void setRange(Range range, boolean turnOffAutoRange,
0503:                    boolean notify) {
0504:                if (range == null) {
0505:                    throw new IllegalArgumentException("Null 'range' argument.");
0506:                }
0507:                // usually the range will be a DateRange, but if it isn't do a 
0508:                // conversion...
0509:                if (!(range instanceof  DateRange)) {
0510:                    range = new DateRange(range);
0511:                }
0512:                super .setRange(range, turnOffAutoRange, notify);
0513:            }
0514:
0515:            /**
0516:             * Sets the axis range and sends an {@link AxisChangeEvent} to all 
0517:             * registered listeners.
0518:             *
0519:             * @param lower  the lower bound for the axis.
0520:             * @param upper  the upper bound for the axis.
0521:             */
0522:            public void setRange(Date lower, Date upper) {
0523:                if (lower.getTime() >= upper.getTime()) {
0524:                    throw new IllegalArgumentException(
0525:                            "Requires 'lower' < 'upper'.");
0526:                }
0527:                setRange(new DateRange(lower, upper));
0528:            }
0529:
0530:            /**
0531:             * Sets the axis range and sends an {@link AxisChangeEvent} to all 
0532:             * registered listeners.
0533:             *
0534:             * @param lower  the lower bound for the axis.
0535:             * @param upper  the upper bound for the axis.
0536:             */
0537:            public void setRange(double lower, double upper) {
0538:                if (lower >= upper) {
0539:                    throw new IllegalArgumentException(
0540:                            "Requires 'lower' < 'upper'.");
0541:                }
0542:                setRange(new DateRange(lower, upper));
0543:            }
0544:
0545:            /**
0546:             * Returns the earliest date visible on the axis.
0547:             *
0548:             * @return The date.
0549:             * 
0550:             * @see #setMinimumDate(Date)
0551:             * @see #getMaximumDate()
0552:             */
0553:            public Date getMinimumDate() {
0554:                Date result = null;
0555:                Range range = getRange();
0556:                if (range instanceof  DateRange) {
0557:                    DateRange r = (DateRange) range;
0558:                    result = r.getLowerDate();
0559:                } else {
0560:                    result = new Date((long) range.getLowerBound());
0561:                }
0562:                return result;
0563:            }
0564:
0565:            /**
0566:             * Sets the minimum date visible on the axis and sends an 
0567:             * {@link AxisChangeEvent} to all registered listeners.  If 
0568:             * <code>date</code> is on or after the current maximum date for 
0569:             * the axis, the maximum date will be shifted to preserve the current
0570:             * length of the axis.
0571:             *
0572:             * @param date  the date (<code>null</code> not permitted).
0573:             * 
0574:             * @see #getMinimumDate()
0575:             * @see #setMaximumDate(Date)
0576:             */
0577:            public void setMinimumDate(Date date) {
0578:                if (date == null) {
0579:                    throw new IllegalArgumentException("Null 'date' argument.");
0580:                }
0581:                // check the new minimum date relative to the current maximum date
0582:                Date maxDate = getMaximumDate();
0583:                long maxMillis = maxDate.getTime();
0584:                long newMinMillis = date.getTime();
0585:                if (maxMillis <= newMinMillis) {
0586:                    Date oldMin = getMinimumDate();
0587:                    long length = maxMillis - oldMin.getTime();
0588:                    maxDate = new Date(newMinMillis + length);
0589:                }
0590:                setRange(new DateRange(date, maxDate), true, false);
0591:                notifyListeners(new AxisChangeEvent(this ));
0592:            }
0593:
0594:            /**
0595:             * Returns the latest date visible on the axis.
0596:             *
0597:             * @return The date.
0598:             * 
0599:             * @see #setMaximumDate(Date)
0600:             * @see #getMinimumDate()
0601:             */
0602:            public Date getMaximumDate() {
0603:                Date result = null;
0604:                Range range = getRange();
0605:                if (range instanceof  DateRange) {
0606:                    DateRange r = (DateRange) range;
0607:                    result = r.getUpperDate();
0608:                } else {
0609:                    result = new Date((long) range.getUpperBound());
0610:                }
0611:                return result;
0612:            }
0613:
0614:            /**
0615:             * Sets the maximum date visible on the axis and sends an 
0616:             * {@link AxisChangeEvent} to all registered listeners.  If 
0617:             * <code>maximumDate</code> is on or before the current minimum date for 
0618:             * the axis, the minimum date will be shifted to preserve the current
0619:             * length of the axis.
0620:             *
0621:             * @param maximumDate  the date (<code>null</code> not permitted).
0622:             * 
0623:             * @see #getMinimumDate()
0624:             * @see #setMinimumDate(Date)
0625:             */
0626:            public void setMaximumDate(Date maximumDate) {
0627:                if (maximumDate == null) {
0628:                    throw new IllegalArgumentException(
0629:                            "Null 'maximumDate' argument.");
0630:                }
0631:                // check the new maximum date relative to the current minimum date
0632:                Date minDate = getMinimumDate();
0633:                long minMillis = minDate.getTime();
0634:                long newMaxMillis = maximumDate.getTime();
0635:                if (minMillis >= newMaxMillis) {
0636:                    Date oldMax = getMaximumDate();
0637:                    long length = oldMax.getTime() - minMillis;
0638:                    minDate = new Date(newMaxMillis - length);
0639:                }
0640:                setRange(new DateRange(minDate, maximumDate), true, false);
0641:                notifyListeners(new AxisChangeEvent(this ));
0642:            }
0643:
0644:            /**
0645:             * Returns the tick mark position (start, middle or end of the time period).
0646:             *
0647:             * @return The position (never <code>null</code>).
0648:             */
0649:            public DateTickMarkPosition getTickMarkPosition() {
0650:                return this .tickMarkPosition;
0651:            }
0652:
0653:            /**
0654:             * Sets the tick mark position (start, middle or end of the time period) 
0655:             * and sends an {@link AxisChangeEvent} to all registered listeners.
0656:             *
0657:             * @param position  the position (<code>null</code> not permitted).
0658:             */
0659:            public void setTickMarkPosition(DateTickMarkPosition position) {
0660:                if (position == null) {
0661:                    throw new IllegalArgumentException(
0662:                            "Null 'position' argument.");
0663:                }
0664:                this .tickMarkPosition = position;
0665:                notifyListeners(new AxisChangeEvent(this ));
0666:            }
0667:
0668:            /**
0669:             * Configures the axis to work with the specified plot.  If the axis has
0670:             * auto-scaling, then sets the maximum and minimum values.
0671:             */
0672:            public void configure() {
0673:                if (isAutoRange()) {
0674:                    autoAdjustRange();
0675:                }
0676:            }
0677:
0678:            /**
0679:             * Returns <code>true</code> if the axis hides this value, and 
0680:             * <code>false</code> otherwise.
0681:             *
0682:             * @param millis  the data value.
0683:             *
0684:             * @return A value.
0685:             */
0686:            public boolean isHiddenValue(long millis) {
0687:                return (!this .timeline.containsDomainValue(new Date(millis)));
0688:            }
0689:
0690:            /**
0691:             * Translates the data value to the display coordinates (Java 2D User Space)
0692:             * of the chart.
0693:             *
0694:             * @param value  the date to be plotted.
0695:             * @param area  the rectangle (in Java2D space) where the data is to be 
0696:             *              plotted.
0697:             * @param edge  the axis location.
0698:             *
0699:             * @return The coordinate corresponding to the supplied data value.
0700:             */
0701:            public double valueToJava2D(double value, Rectangle2D area,
0702:                    RectangleEdge edge) {
0703:
0704:                value = this .timeline.toTimelineValue((long) value);
0705:
0706:                DateRange range = (DateRange) getRange();
0707:                double axisMin = this .timeline.toTimelineValue(range
0708:                        .getLowerDate());
0709:                double axisMax = this .timeline.toTimelineValue(range
0710:                        .getUpperDate());
0711:                double result = 0.0;
0712:                if (RectangleEdge.isTopOrBottom(edge)) {
0713:                    double minX = area.getX();
0714:                    double maxX = area.getMaxX();
0715:                    if (isInverted()) {
0716:                        result = maxX
0717:                                + ((value - axisMin) / (axisMax - axisMin))
0718:                                * (minX - maxX);
0719:                    } else {
0720:                        result = minX
0721:                                + ((value - axisMin) / (axisMax - axisMin))
0722:                                * (maxX - minX);
0723:                    }
0724:                } else if (RectangleEdge.isLeftOrRight(edge)) {
0725:                    double minY = area.getMinY();
0726:                    double maxY = area.getMaxY();
0727:                    if (isInverted()) {
0728:                        result = minY
0729:                                + (((value - axisMin) / (axisMax - axisMin)) * (maxY - minY));
0730:                    } else {
0731:                        result = maxY
0732:                                - (((value - axisMin) / (axisMax - axisMin)) * (maxY - minY));
0733:                    }
0734:                }
0735:                return result;
0736:
0737:            }
0738:
0739:            /**
0740:             * Translates a date to Java2D coordinates, based on the range displayed by
0741:             * this axis for the specified data area.
0742:             *
0743:             * @param date  the date.
0744:             * @param area  the rectangle (in Java2D space) where the data is to be
0745:             *              plotted.
0746:             * @param edge  the axis location.
0747:             *
0748:             * @return The coordinate corresponding to the supplied date.
0749:             */
0750:            public double dateToJava2D(Date date, Rectangle2D area,
0751:                    RectangleEdge edge) {
0752:                double value = date.getTime();
0753:                return valueToJava2D(value, area, edge);
0754:            }
0755:
0756:            /**
0757:             * Translates a Java2D coordinate into the corresponding data value.  To 
0758:             * perform this translation, you need to know the area used for plotting 
0759:             * data, and which edge the axis is located on.
0760:             *
0761:             * @param java2DValue  the coordinate in Java2D space.
0762:             * @param area  the rectangle (in Java2D space) where the data is to be 
0763:             *              plotted.
0764:             * @param edge  the axis location.
0765:             *
0766:             * @return A data value.
0767:             */
0768:            public double java2DToValue(double java2DValue, Rectangle2D area,
0769:                    RectangleEdge edge) {
0770:
0771:                DateRange range = (DateRange) getRange();
0772:                double axisMin = this .timeline.toTimelineValue(range
0773:                        .getLowerDate());
0774:                double axisMax = this .timeline.toTimelineValue(range
0775:                        .getUpperDate());
0776:
0777:                double min = 0.0;
0778:                double max = 0.0;
0779:                if (RectangleEdge.isTopOrBottom(edge)) {
0780:                    min = area.getX();
0781:                    max = area.getMaxX();
0782:                } else if (RectangleEdge.isLeftOrRight(edge)) {
0783:                    min = area.getMaxY();
0784:                    max = area.getY();
0785:                }
0786:
0787:                double result;
0788:                if (isInverted()) {
0789:                    result = axisMax
0790:                            - ((java2DValue - min) / (max - min) * (axisMax - axisMin));
0791:                } else {
0792:                    result = axisMin
0793:                            + ((java2DValue - min) / (max - min) * (axisMax - axisMin));
0794:                }
0795:
0796:                return this .timeline.toMillisecond((long) result);
0797:            }
0798:
0799:            /**
0800:             * Calculates the value of the lowest visible tick on the axis.
0801:             *
0802:             * @param unit  date unit to use.
0803:             *
0804:             * @return The value of the lowest visible tick on the axis.
0805:             */
0806:            public Date calculateLowestVisibleTickValue(DateTickUnit unit) {
0807:                return nextStandardDate(getMinimumDate(), unit);
0808:            }
0809:
0810:            /**
0811:             * Calculates the value of the highest visible tick on the axis.
0812:             *
0813:             * @param unit  date unit to use.
0814:             *
0815:             * @return The value of the highest visible tick on the axis.
0816:             */
0817:            public Date calculateHighestVisibleTickValue(DateTickUnit unit) {
0818:                return previousStandardDate(getMaximumDate(), unit);
0819:            }
0820:
0821:            /**
0822:             * Returns the previous "standard" date, for a given date and tick unit.
0823:             *
0824:             * @param date  the reference date.
0825:             * @param unit  the tick unit.
0826:             *
0827:             * @return The previous "standard" date.
0828:             */
0829:            protected Date previousStandardDate(Date date, DateTickUnit unit) {
0830:
0831:                int milliseconds;
0832:                int seconds;
0833:                int minutes;
0834:                int hours;
0835:                int days;
0836:                int months;
0837:                int years;
0838:
0839:                Calendar calendar = Calendar.getInstance(this .timeZone);
0840:                calendar.setTime(date);
0841:                int count = unit.getCount();
0842:                int current = calendar.get(unit.getCalendarField());
0843:                int value = count * (current / count);
0844:
0845:                switch (unit.getUnit()) {
0846:
0847:                case (DateTickUnit.MILLISECOND):
0848:                    years = calendar.get(Calendar.YEAR);
0849:                    months = calendar.get(Calendar.MONTH);
0850:                    days = calendar.get(Calendar.DATE);
0851:                    hours = calendar.get(Calendar.HOUR_OF_DAY);
0852:                    minutes = calendar.get(Calendar.MINUTE);
0853:                    seconds = calendar.get(Calendar.SECOND);
0854:                    calendar.set(years, months, days, hours, minutes, seconds);
0855:                    calendar.set(Calendar.MILLISECOND, value);
0856:                    Date mm = calendar.getTime();
0857:                    if (mm.getTime() >= date.getTime()) {
0858:                        calendar.set(Calendar.MILLISECOND, value - 1);
0859:                        mm = calendar.getTime();
0860:                    }
0861:                    return calendar.getTime();
0862:
0863:                case (DateTickUnit.SECOND):
0864:                    years = calendar.get(Calendar.YEAR);
0865:                    months = calendar.get(Calendar.MONTH);
0866:                    days = calendar.get(Calendar.DATE);
0867:                    hours = calendar.get(Calendar.HOUR_OF_DAY);
0868:                    minutes = calendar.get(Calendar.MINUTE);
0869:                    if (this .tickMarkPosition == DateTickMarkPosition.START) {
0870:                        milliseconds = 0;
0871:                    } else if (this .tickMarkPosition == DateTickMarkPosition.MIDDLE) {
0872:                        milliseconds = 500;
0873:                    } else {
0874:                        milliseconds = 999;
0875:                    }
0876:                    calendar.set(Calendar.MILLISECOND, milliseconds);
0877:                    calendar.set(years, months, days, hours, minutes, value);
0878:                    Date dd = calendar.getTime();
0879:                    if (dd.getTime() >= date.getTime()) {
0880:                        calendar.set(Calendar.SECOND, value - 1);
0881:                        dd = calendar.getTime();
0882:                    }
0883:                    return calendar.getTime();
0884:
0885:                case (DateTickUnit.MINUTE):
0886:                    years = calendar.get(Calendar.YEAR);
0887:                    months = calendar.get(Calendar.MONTH);
0888:                    days = calendar.get(Calendar.DATE);
0889:                    hours = calendar.get(Calendar.HOUR_OF_DAY);
0890:                    if (this .tickMarkPosition == DateTickMarkPosition.START) {
0891:                        seconds = 0;
0892:                    } else if (this .tickMarkPosition == DateTickMarkPosition.MIDDLE) {
0893:                        seconds = 30;
0894:                    } else {
0895:                        seconds = 59;
0896:                    }
0897:                    calendar.clear(Calendar.MILLISECOND);
0898:                    calendar.set(years, months, days, hours, value, seconds);
0899:                    Date d0 = calendar.getTime();
0900:                    if (d0.getTime() >= date.getTime()) {
0901:                        calendar.set(Calendar.MINUTE, value - 1);
0902:                        d0 = calendar.getTime();
0903:                    }
0904:                    return d0;
0905:
0906:                case (DateTickUnit.HOUR):
0907:                    years = calendar.get(Calendar.YEAR);
0908:                    months = calendar.get(Calendar.MONTH);
0909:                    days = calendar.get(Calendar.DATE);
0910:                    if (this .tickMarkPosition == DateTickMarkPosition.START) {
0911:                        minutes = 0;
0912:                        seconds = 0;
0913:                    } else if (this .tickMarkPosition == DateTickMarkPosition.MIDDLE) {
0914:                        minutes = 30;
0915:                        seconds = 0;
0916:                    } else {
0917:                        minutes = 59;
0918:                        seconds = 59;
0919:                    }
0920:                    calendar.clear(Calendar.MILLISECOND);
0921:                    calendar.set(years, months, days, value, minutes, seconds);
0922:                    Date d1 = calendar.getTime();
0923:                    if (d1.getTime() >= date.getTime()) {
0924:                        calendar.set(Calendar.HOUR_OF_DAY, value - 1);
0925:                        d1 = calendar.getTime();
0926:                    }
0927:                    return d1;
0928:
0929:                case (DateTickUnit.DAY):
0930:                    years = calendar.get(Calendar.YEAR);
0931:                    months = calendar.get(Calendar.MONTH);
0932:                    if (this .tickMarkPosition == DateTickMarkPosition.START) {
0933:                        hours = 0;
0934:                        minutes = 0;
0935:                        seconds = 0;
0936:                    } else if (this .tickMarkPosition == DateTickMarkPosition.MIDDLE) {
0937:                        hours = 12;
0938:                        minutes = 0;
0939:                        seconds = 0;
0940:                    } else {
0941:                        hours = 23;
0942:                        minutes = 59;
0943:                        seconds = 59;
0944:                    }
0945:                    calendar.clear(Calendar.MILLISECOND);
0946:                    calendar.set(years, months, value, hours, 0, 0);
0947:                    // long result = calendar.getTimeInMillis();  
0948:                    // won't work with JDK 1.3
0949:                    Date d2 = calendar.getTime();
0950:                    if (d2.getTime() >= date.getTime()) {
0951:                        calendar.set(Calendar.DATE, value - 1);
0952:                        d2 = calendar.getTime();
0953:                    }
0954:                    return d2;
0955:
0956:                case (DateTickUnit.MONTH):
0957:                    years = calendar.get(Calendar.YEAR);
0958:                    calendar.clear(Calendar.MILLISECOND);
0959:                    calendar.set(years, value, 1, 0, 0, 0);
0960:                    Month month = new Month(calendar.getTime(), this .timeZone);
0961:                    Date standardDate = calculateDateForPosition(month,
0962:                            this .tickMarkPosition);
0963:                    long millis = standardDate.getTime();
0964:                    if (millis >= date.getTime()) {
0965:                        month = (Month) month.previous();
0966:                        standardDate = calculateDateForPosition(month,
0967:                                this .tickMarkPosition);
0968:                    }
0969:                    return standardDate;
0970:
0971:                case (DateTickUnit.YEAR):
0972:                    if (this .tickMarkPosition == DateTickMarkPosition.START) {
0973:                        months = 0;
0974:                        days = 1;
0975:                    } else if (this .tickMarkPosition == DateTickMarkPosition.MIDDLE) {
0976:                        months = 6;
0977:                        days = 1;
0978:                    } else {
0979:                        months = 11;
0980:                        days = 31;
0981:                    }
0982:                    calendar.clear(Calendar.MILLISECOND);
0983:                    calendar.set(value, months, days, 0, 0, 0);
0984:                    Date d3 = calendar.getTime();
0985:                    if (d3.getTime() >= date.getTime()) {
0986:                        calendar.set(Calendar.YEAR, value - 1);
0987:                        d3 = calendar.getTime();
0988:                    }
0989:                    return d3;
0990:
0991:                default:
0992:                    return null;
0993:
0994:                }
0995:
0996:            }
0997:
0998:            /**
0999:             * Returns a {@link java.util.Date} corresponding to the specified position
1000:             * within a {@link RegularTimePeriod}.
1001:             *
1002:             * @param period  the period.
1003:             * @param position  the position (<code>null</code> not permitted).
1004:             *
1005:             * @return A date.
1006:             */
1007:            private Date calculateDateForPosition(RegularTimePeriod period,
1008:                    DateTickMarkPosition position) {
1009:
1010:                if (position == null) {
1011:                    throw new IllegalArgumentException(
1012:                            "Null 'position' argument.");
1013:                }
1014:                Date result = null;
1015:                if (position == DateTickMarkPosition.START) {
1016:                    result = new Date(period.getFirstMillisecond());
1017:                } else if (position == DateTickMarkPosition.MIDDLE) {
1018:                    result = new Date(period.getMiddleMillisecond());
1019:                } else if (position == DateTickMarkPosition.END) {
1020:                    result = new Date(period.getLastMillisecond());
1021:                }
1022:                return result;
1023:
1024:            }
1025:
1026:            /**
1027:             * Returns the first "standard" date (based on the specified field and 
1028:             * units).
1029:             *
1030:             * @param date  the reference date.
1031:             * @param unit  the date tick unit.
1032:             *
1033:             * @return The next "standard" date.
1034:             */
1035:            protected Date nextStandardDate(Date date, DateTickUnit unit) {
1036:                Date previous = previousStandardDate(date, unit);
1037:                Calendar calendar = Calendar.getInstance(this .timeZone);
1038:                calendar.setTime(previous);
1039:                calendar.add(unit.getCalendarField(), unit.getCount());
1040:                return calendar.getTime();
1041:            }
1042:
1043:            /**
1044:             * Returns a collection of standard date tick units that uses the default 
1045:             * time zone.  This collection will be used by default, but you are free 
1046:             * to create your own collection if you want to (see the 
1047:             * {@link ValueAxis#setStandardTickUnits(TickUnitSource)} method inherited 
1048:             * from the {@link ValueAxis} class).
1049:             *
1050:             * @return A collection of standard date tick units.
1051:             */
1052:            public static TickUnitSource createStandardDateTickUnits() {
1053:                return createStandardDateTickUnits(TimeZone.getDefault());
1054:            }
1055:
1056:            /**
1057:             * Returns a collection of standard date tick units.  This collection will 
1058:             * be used by default, but you are free to create your own collection if 
1059:             * you want to (see the 
1060:             * {@link ValueAxis#setStandardTickUnits(TickUnitSource)} method inherited 
1061:             * from the {@link ValueAxis} class).
1062:             *
1063:             * @param zone  the time zone (<code>null</code> not permitted).
1064:             * 
1065:             * @return A collection of standard date tick units.
1066:             */
1067:            public static TickUnitSource createStandardDateTickUnits(
1068:                    TimeZone zone) {
1069:
1070:                if (zone == null) {
1071:                    throw new IllegalArgumentException("Null 'zone' argument.");
1072:                }
1073:                TickUnits units = new TickUnits();
1074:
1075:                // date formatters
1076:                DateFormat f1 = new SimpleDateFormat("HH:mm:ss.SSS");
1077:                DateFormat f2 = new SimpleDateFormat("HH:mm:ss");
1078:                DateFormat f3 = new SimpleDateFormat("HH:mm");
1079:                DateFormat f4 = new SimpleDateFormat("d-MMM, HH:mm");
1080:                DateFormat f5 = new SimpleDateFormat("d-MMM");
1081:                DateFormat f6 = new SimpleDateFormat("MMM-yyyy");
1082:                DateFormat f7 = new SimpleDateFormat("yyyy");
1083:
1084:                f1.setTimeZone(zone);
1085:                f2.setTimeZone(zone);
1086:                f3.setTimeZone(zone);
1087:                f4.setTimeZone(zone);
1088:                f5.setTimeZone(zone);
1089:                f6.setTimeZone(zone);
1090:                f7.setTimeZone(zone);
1091:
1092:                // milliseconds
1093:                units.add(new DateTickUnit(DateTickUnit.MILLISECOND, 1, f1));
1094:                units.add(new DateTickUnit(DateTickUnit.MILLISECOND, 5,
1095:                        DateTickUnit.MILLISECOND, 1, f1));
1096:                units.add(new DateTickUnit(DateTickUnit.MILLISECOND, 10,
1097:                        DateTickUnit.MILLISECOND, 1, f1));
1098:                units.add(new DateTickUnit(DateTickUnit.MILLISECOND, 25,
1099:                        DateTickUnit.MILLISECOND, 5, f1));
1100:                units.add(new DateTickUnit(DateTickUnit.MILLISECOND, 50,
1101:                        DateTickUnit.MILLISECOND, 10, f1));
1102:                units.add(new DateTickUnit(DateTickUnit.MILLISECOND, 100,
1103:                        DateTickUnit.MILLISECOND, 10, f1));
1104:                units.add(new DateTickUnit(DateTickUnit.MILLISECOND, 250,
1105:                        DateTickUnit.MILLISECOND, 10, f1));
1106:                units.add(new DateTickUnit(DateTickUnit.MILLISECOND, 500,
1107:                        DateTickUnit.MILLISECOND, 50, f1));
1108:
1109:                // seconds
1110:                units.add(new DateTickUnit(DateTickUnit.SECOND, 1,
1111:                        DateTickUnit.MILLISECOND, 50, f2));
1112:                units.add(new DateTickUnit(DateTickUnit.SECOND, 5,
1113:                        DateTickUnit.SECOND, 1, f2));
1114:                units.add(new DateTickUnit(DateTickUnit.SECOND, 10,
1115:                        DateTickUnit.SECOND, 1, f2));
1116:                units.add(new DateTickUnit(DateTickUnit.SECOND, 30,
1117:                        DateTickUnit.SECOND, 5, f2));
1118:
1119:                // minutes
1120:                units.add(new DateTickUnit(DateTickUnit.MINUTE, 1,
1121:                        DateTickUnit.SECOND, 5, f3));
1122:                units.add(new DateTickUnit(DateTickUnit.MINUTE, 2,
1123:                        DateTickUnit.SECOND, 10, f3));
1124:                units.add(new DateTickUnit(DateTickUnit.MINUTE, 5,
1125:                        DateTickUnit.MINUTE, 1, f3));
1126:                units.add(new DateTickUnit(DateTickUnit.MINUTE, 10,
1127:                        DateTickUnit.MINUTE, 1, f3));
1128:                units.add(new DateTickUnit(DateTickUnit.MINUTE, 15,
1129:                        DateTickUnit.MINUTE, 5, f3));
1130:                units.add(new DateTickUnit(DateTickUnit.MINUTE, 20,
1131:                        DateTickUnit.MINUTE, 5, f3));
1132:                units.add(new DateTickUnit(DateTickUnit.MINUTE, 30,
1133:                        DateTickUnit.MINUTE, 5, f3));
1134:
1135:                // hours
1136:                units.add(new DateTickUnit(DateTickUnit.HOUR, 1,
1137:                        DateTickUnit.MINUTE, 5, f3));
1138:                units.add(new DateTickUnit(DateTickUnit.HOUR, 2,
1139:                        DateTickUnit.MINUTE, 10, f3));
1140:                units.add(new DateTickUnit(DateTickUnit.HOUR, 4,
1141:                        DateTickUnit.MINUTE, 30, f3));
1142:                units.add(new DateTickUnit(DateTickUnit.HOUR, 6,
1143:                        DateTickUnit.HOUR, 1, f3));
1144:                units.add(new DateTickUnit(DateTickUnit.HOUR, 12,
1145:                        DateTickUnit.HOUR, 1, f4));
1146:
1147:                // days
1148:                units.add(new DateTickUnit(DateTickUnit.DAY, 1,
1149:                        DateTickUnit.HOUR, 1, f5));
1150:                units.add(new DateTickUnit(DateTickUnit.DAY, 2,
1151:                        DateTickUnit.HOUR, 1, f5));
1152:                units.add(new DateTickUnit(DateTickUnit.DAY, 7,
1153:                        DateTickUnit.DAY, 1, f5));
1154:                units.add(new DateTickUnit(DateTickUnit.DAY, 15,
1155:                        DateTickUnit.DAY, 1, f5));
1156:
1157:                // months
1158:                units.add(new DateTickUnit(DateTickUnit.MONTH, 1,
1159:                        DateTickUnit.DAY, 1, f6));
1160:                units.add(new DateTickUnit(DateTickUnit.MONTH, 2,
1161:                        DateTickUnit.DAY, 1, f6));
1162:                units.add(new DateTickUnit(DateTickUnit.MONTH, 3,
1163:                        DateTickUnit.MONTH, 1, f6));
1164:                units.add(new DateTickUnit(DateTickUnit.MONTH, 4,
1165:                        DateTickUnit.MONTH, 1, f6));
1166:                units.add(new DateTickUnit(DateTickUnit.MONTH, 6,
1167:                        DateTickUnit.MONTH, 1, f6));
1168:
1169:                // years
1170:                units.add(new DateTickUnit(DateTickUnit.YEAR, 1,
1171:                        DateTickUnit.MONTH, 1, f7));
1172:                units.add(new DateTickUnit(DateTickUnit.YEAR, 2,
1173:                        DateTickUnit.MONTH, 3, f7));
1174:                units.add(new DateTickUnit(DateTickUnit.YEAR, 5,
1175:                        DateTickUnit.YEAR, 1, f7));
1176:                units.add(new DateTickUnit(DateTickUnit.YEAR, 10,
1177:                        DateTickUnit.YEAR, 1, f7));
1178:                units.add(new DateTickUnit(DateTickUnit.YEAR, 25,
1179:                        DateTickUnit.YEAR, 5, f7));
1180:                units.add(new DateTickUnit(DateTickUnit.YEAR, 50,
1181:                        DateTickUnit.YEAR, 10, f7));
1182:                units.add(new DateTickUnit(DateTickUnit.YEAR, 100,
1183:                        DateTickUnit.YEAR, 20, f7));
1184:
1185:                return units;
1186:
1187:            }
1188:
1189:            /**
1190:             * Rescales the axis to ensure that all data is visible.
1191:             */
1192:            protected void autoAdjustRange() {
1193:
1194:                Plot plot = getPlot();
1195:
1196:                if (plot == null) {
1197:                    return; // no plot, no data
1198:                }
1199:
1200:                if (plot instanceof  ValueAxisPlot) {
1201:                    ValueAxisPlot vap = (ValueAxisPlot) plot;
1202:
1203:                    Range r = vap.getDataRange(this );
1204:                    if (r == null) {
1205:                        if (this .timeline instanceof  SegmentedTimeline) {
1206:                            //Timeline hasn't method getStartTime()
1207:                            r = new DateRange(
1208:                                    ((SegmentedTimeline) this .timeline)
1209:                                            .getStartTime(),
1210:                                    ((SegmentedTimeline) this .timeline)
1211:                                            .getStartTime() + 1);
1212:                        } else {
1213:                            r = new DateRange();
1214:                        }
1215:                    }
1216:
1217:                    long upper = this .timeline.toTimelineValue((long) r
1218:                            .getUpperBound());
1219:                    long lower;
1220:                    long fixedAutoRange = (long) getFixedAutoRange();
1221:                    if (fixedAutoRange > 0.0) {
1222:                        lower = upper - fixedAutoRange;
1223:                    } else {
1224:                        lower = this .timeline.toTimelineValue((long) r
1225:                                .getLowerBound());
1226:                        double range = upper - lower;
1227:                        long minRange = (long) getAutoRangeMinimumSize();
1228:                        if (range < minRange) {
1229:                            long expand = (long) (minRange - range) / 2;
1230:                            upper = upper + expand;
1231:                            lower = lower - expand;
1232:                        }
1233:                        upper = upper + (long) (range * getUpperMargin());
1234:                        lower = lower - (long) (range * getLowerMargin());
1235:                    }
1236:
1237:                    upper = this .timeline.toMillisecond(upper);
1238:                    lower = this .timeline.toMillisecond(lower);
1239:                    DateRange dr = new DateRange(new Date(lower), new Date(
1240:                            upper));
1241:                    setRange(dr, false, false);
1242:                }
1243:
1244:            }
1245:
1246:            /**
1247:             * Selects an appropriate tick value for the axis.  The strategy is to
1248:             * display as many ticks as possible (selected from an array of 'standard'
1249:             * tick units) without the labels overlapping.
1250:             *
1251:             * @param g2  the graphics device.
1252:             * @param dataArea  the area defined by the axes.
1253:             * @param edge  the axis location.
1254:             */
1255:            protected void selectAutoTickUnit(Graphics2D g2,
1256:                    Rectangle2D dataArea, RectangleEdge edge) {
1257:
1258:                if (RectangleEdge.isTopOrBottom(edge)) {
1259:                    selectHorizontalAutoTickUnit(g2, dataArea, edge);
1260:                } else if (RectangleEdge.isLeftOrRight(edge)) {
1261:                    selectVerticalAutoTickUnit(g2, dataArea, edge);
1262:                }
1263:
1264:            }
1265:
1266:            /**
1267:             * Selects an appropriate tick size for the axis.  The strategy is to
1268:             * display as many ticks as possible (selected from a collection of 
1269:             * 'standard' tick units) without the labels overlapping.
1270:             *
1271:             * @param g2  the graphics device.
1272:             * @param dataArea  the area defined by the axes.
1273:             * @param edge  the axis location.
1274:             */
1275:            protected void selectHorizontalAutoTickUnit(Graphics2D g2,
1276:                    Rectangle2D dataArea, RectangleEdge edge) {
1277:
1278:                long shift = 0;
1279:                if (this .timeline instanceof  SegmentedTimeline) {
1280:                    shift = ((SegmentedTimeline) this .timeline).getStartTime();
1281:                }
1282:                double zero = valueToJava2D(shift + 0.0, dataArea, edge);
1283:                double tickLabelWidth = estimateMaximumTickLabelWidth(g2,
1284:                        getTickUnit());
1285:
1286:                // start with the current tick unit...
1287:                TickUnitSource tickUnits = getStandardTickUnits();
1288:                TickUnit unit1 = tickUnits.getCeilingTickUnit(getTickUnit());
1289:                double x1 = valueToJava2D(shift + unit1.getSize(), dataArea,
1290:                        edge);
1291:                double unit1Width = Math.abs(x1 - zero);
1292:
1293:                // then extrapolate...
1294:                double guess = (tickLabelWidth / unit1Width) * unit1.getSize();
1295:                DateTickUnit unit2 = (DateTickUnit) tickUnits
1296:                        .getCeilingTickUnit(guess);
1297:                double x2 = valueToJava2D(shift + unit2.getSize(), dataArea,
1298:                        edge);
1299:                double unit2Width = Math.abs(x2 - zero);
1300:                tickLabelWidth = estimateMaximumTickLabelWidth(g2, unit2);
1301:                if (tickLabelWidth > unit2Width) {
1302:                    unit2 = (DateTickUnit) tickUnits.getLargerTickUnit(unit2);
1303:                }
1304:                setTickUnit(unit2, false, false);
1305:            }
1306:
1307:            /**
1308:             * Selects an appropriate tick size for the axis.  The strategy is to
1309:             * display as many ticks as possible (selected from a collection of 
1310:             * 'standard' tick units) without the labels overlapping.
1311:             *
1312:             * @param g2  the graphics device.
1313:             * @param dataArea  the area in which the plot should be drawn.
1314:             * @param edge  the axis location.
1315:             */
1316:            protected void selectVerticalAutoTickUnit(Graphics2D g2,
1317:                    Rectangle2D dataArea, RectangleEdge edge) {
1318:
1319:                // start with the current tick unit...
1320:                TickUnitSource tickUnits = getStandardTickUnits();
1321:                double zero = valueToJava2D(0.0, dataArea, edge);
1322:
1323:                // start with a unit that is at least 1/10th of the axis length
1324:                double estimate1 = getRange().getLength() / 10.0;
1325:                DateTickUnit candidate1 = (DateTickUnit) tickUnits
1326:                        .getCeilingTickUnit(estimate1);
1327:                double labelHeight1 = estimateMaximumTickLabelHeight(g2,
1328:                        candidate1);
1329:                double y1 = valueToJava2D(candidate1.getSize(), dataArea, edge);
1330:                double candidate1UnitHeight = Math.abs(y1 - zero);
1331:
1332:                // now extrapolate based on label height and unit height...
1333:                double estimate2 = (labelHeight1 / candidate1UnitHeight)
1334:                        * candidate1.getSize();
1335:                DateTickUnit candidate2 = (DateTickUnit) tickUnits
1336:                        .getCeilingTickUnit(estimate2);
1337:                double labelHeight2 = estimateMaximumTickLabelHeight(g2,
1338:                        candidate2);
1339:                double y2 = valueToJava2D(candidate2.getSize(), dataArea, edge);
1340:                double unit2Height = Math.abs(y2 - zero);
1341:
1342:                // make final selection...
1343:                DateTickUnit finalUnit;
1344:                if (labelHeight2 < unit2Height) {
1345:                    finalUnit = candidate2;
1346:                } else {
1347:                    finalUnit = (DateTickUnit) tickUnits
1348:                            .getLargerTickUnit(candidate2);
1349:                }
1350:                setTickUnit(finalUnit, false, false);
1351:
1352:            }
1353:
1354:            /**
1355:             * Estimates the maximum width of the tick labels, assuming the specified 
1356:             * tick unit is used.
1357:             * <P>
1358:             * Rather than computing the string bounds of every tick on the axis, we
1359:             * just look at two values: the lower bound and the upper bound for the 
1360:             * axis.  These two values will usually be representative.
1361:             *
1362:             * @param g2  the graphics device.
1363:             * @param unit  the tick unit to use for calculation.
1364:             *
1365:             * @return The estimated maximum width of the tick labels.
1366:             */
1367:            private double estimateMaximumTickLabelWidth(Graphics2D g2,
1368:                    DateTickUnit unit) {
1369:
1370:                RectangleInsets tickLabelInsets = getTickLabelInsets();
1371:                double result = tickLabelInsets.getLeft()
1372:                        + tickLabelInsets.getRight();
1373:
1374:                Font tickLabelFont = getTickLabelFont();
1375:                FontRenderContext frc = g2.getFontRenderContext();
1376:                LineMetrics lm = tickLabelFont.getLineMetrics("ABCxyz", frc);
1377:                if (isVerticalTickLabels()) {
1378:                    // all tick labels have the same width (equal to the height of 
1379:                    // the font)...
1380:                    result += lm.getHeight();
1381:                } else {
1382:                    // look at lower and upper bounds...
1383:                    DateRange range = (DateRange) getRange();
1384:                    Date lower = range.getLowerDate();
1385:                    Date upper = range.getUpperDate();
1386:                    String lowerStr = null;
1387:                    String upperStr = null;
1388:                    DateFormat formatter = getDateFormatOverride();
1389:                    if (formatter != null) {
1390:                        lowerStr = formatter.format(lower);
1391:                        upperStr = formatter.format(upper);
1392:                    } else {
1393:                        lowerStr = unit.dateToString(lower);
1394:                        upperStr = unit.dateToString(upper);
1395:                    }
1396:                    FontMetrics fm = g2.getFontMetrics(tickLabelFont);
1397:                    double w1 = fm.stringWidth(lowerStr);
1398:                    double w2 = fm.stringWidth(upperStr);
1399:                    result += Math.max(w1, w2);
1400:                }
1401:
1402:                return result;
1403:
1404:            }
1405:
1406:            /**
1407:             * Estimates the maximum width of the tick labels, assuming the specified 
1408:             * tick unit is used.
1409:             * <P>
1410:             * Rather than computing the string bounds of every tick on the axis, we 
1411:             * just look at two values: the lower bound and the upper bound for the 
1412:             * axis.  These two values will usually be representative.
1413:             *
1414:             * @param g2  the graphics device.
1415:             * @param unit  the tick unit to use for calculation.
1416:             *
1417:             * @return The estimated maximum width of the tick labels.
1418:             */
1419:            private double estimateMaximumTickLabelHeight(Graphics2D g2,
1420:                    DateTickUnit unit) {
1421:
1422:                RectangleInsets tickLabelInsets = getTickLabelInsets();
1423:                double result = tickLabelInsets.getTop()
1424:                        + tickLabelInsets.getBottom();
1425:
1426:                Font tickLabelFont = getTickLabelFont();
1427:                FontRenderContext frc = g2.getFontRenderContext();
1428:                LineMetrics lm = tickLabelFont.getLineMetrics("ABCxyz", frc);
1429:                if (!isVerticalTickLabels()) {
1430:                    // all tick labels have the same width (equal to the height of 
1431:                    // the font)...
1432:                    result += lm.getHeight();
1433:                } else {
1434:                    // look at lower and upper bounds...
1435:                    DateRange range = (DateRange) getRange();
1436:                    Date lower = range.getLowerDate();
1437:                    Date upper = range.getUpperDate();
1438:                    String lowerStr = null;
1439:                    String upperStr = null;
1440:                    DateFormat formatter = getDateFormatOverride();
1441:                    if (formatter != null) {
1442:                        lowerStr = formatter.format(lower);
1443:                        upperStr = formatter.format(upper);
1444:                    } else {
1445:                        lowerStr = unit.dateToString(lower);
1446:                        upperStr = unit.dateToString(upper);
1447:                    }
1448:                    FontMetrics fm = g2.getFontMetrics(tickLabelFont);
1449:                    double w1 = fm.stringWidth(lowerStr);
1450:                    double w2 = fm.stringWidth(upperStr);
1451:                    result += Math.max(w1, w2);
1452:                }
1453:
1454:                return result;
1455:
1456:            }
1457:
1458:            /**
1459:             * Calculates the positions of the tick labels for the axis, storing the 
1460:             * results in the tick label list (ready for drawing).
1461:             *
1462:             * @param g2  the graphics device.
1463:             * @param state  the axis state.
1464:             * @param dataArea  the area in which the plot should be drawn.
1465:             * @param edge  the location of the axis.
1466:             *
1467:             * @return A list of ticks.
1468:             */
1469:            public List refreshTicks(Graphics2D g2, AxisState state,
1470:                    Rectangle2D dataArea, RectangleEdge edge) {
1471:
1472:                List result = null;
1473:                if (RectangleEdge.isTopOrBottom(edge)) {
1474:                    result = refreshTicksHorizontal(g2, dataArea, edge);
1475:                } else if (RectangleEdge.isLeftOrRight(edge)) {
1476:                    result = refreshTicksVertical(g2, dataArea, edge);
1477:                }
1478:                return result;
1479:
1480:            }
1481:
1482:            /**
1483:             * Recalculates the ticks for the date axis.
1484:             *
1485:             * @param g2  the graphics device.
1486:             * @param dataArea  the area in which the data is to be drawn.
1487:             * @param edge  the location of the axis.
1488:             *
1489:             * @return A list of ticks.
1490:             */
1491:            protected List refreshTicksHorizontal(Graphics2D g2,
1492:                    Rectangle2D dataArea, RectangleEdge edge) {
1493:
1494:                List result = new java.util.ArrayList();
1495:
1496:                Font tickLabelFont = getTickLabelFont();
1497:                g2.setFont(tickLabelFont);
1498:
1499:                if (isAutoTickUnitSelection()) {
1500:                    selectAutoTickUnit(g2, dataArea, edge);
1501:                }
1502:
1503:                DateTickUnit unit = getTickUnit();
1504:                Date tickDate = calculateLowestVisibleTickValue(unit);
1505:                Date upperDate = getMaximumDate();
1506:
1507:                while (tickDate.before(upperDate)) {
1508:
1509:                    if (!isHiddenValue(tickDate.getTime())) {
1510:                        // work out the value, label and position
1511:                        String tickLabel;
1512:                        DateFormat formatter = getDateFormatOverride();
1513:                        if (formatter != null) {
1514:                            tickLabel = formatter.format(tickDate);
1515:                        } else {
1516:                            tickLabel = this .tickUnit.dateToString(tickDate);
1517:                        }
1518:                        TextAnchor anchor = null;
1519:                        TextAnchor rotationAnchor = null;
1520:                        double angle = 0.0;
1521:                        if (isVerticalTickLabels()) {
1522:                            anchor = TextAnchor.CENTER_RIGHT;
1523:                            rotationAnchor = TextAnchor.CENTER_RIGHT;
1524:                            if (edge == RectangleEdge.TOP) {
1525:                                angle = Math.PI / 2.0;
1526:                            } else {
1527:                                angle = -Math.PI / 2.0;
1528:                            }
1529:                        } else {
1530:                            if (edge == RectangleEdge.TOP) {
1531:                                anchor = TextAnchor.BOTTOM_CENTER;
1532:                                rotationAnchor = TextAnchor.BOTTOM_CENTER;
1533:                            } else {
1534:                                anchor = TextAnchor.TOP_CENTER;
1535:                                rotationAnchor = TextAnchor.TOP_CENTER;
1536:                            }
1537:                        }
1538:
1539:                        Tick tick = new DateTick(tickDate, tickLabel, anchor,
1540:                                rotationAnchor, angle);
1541:                        result.add(tick);
1542:                        tickDate = unit.addToDate(tickDate, this .timeZone);
1543:                    } else {
1544:                        tickDate = unit.rollDate(tickDate, this .timeZone);
1545:                        continue;
1546:                    }
1547:
1548:                    // could add a flag to make the following correction optional...
1549:                    switch (unit.getUnit()) {
1550:
1551:                    case (DateTickUnit.MILLISECOND):
1552:                    case (DateTickUnit.SECOND):
1553:                    case (DateTickUnit.MINUTE):
1554:                    case (DateTickUnit.HOUR):
1555:                    case (DateTickUnit.DAY):
1556:                        break;
1557:                    case (DateTickUnit.MONTH):
1558:                        tickDate = calculateDateForPosition(new Month(tickDate,
1559:                                this .timeZone), this .tickMarkPosition);
1560:                        break;
1561:                    case (DateTickUnit.YEAR):
1562:                        tickDate = calculateDateForPosition(new Year(tickDate,
1563:                                this .timeZone), this .tickMarkPosition);
1564:                        break;
1565:
1566:                    default:
1567:                        break;
1568:
1569:                    }
1570:
1571:                }
1572:                return result;
1573:
1574:            }
1575:
1576:            /**
1577:             * Recalculates the ticks for the date axis.
1578:             *
1579:             * @param g2  the graphics device.
1580:             * @param dataArea  the area in which the plot should be drawn.
1581:             * @param edge  the location of the axis.
1582:             *
1583:             * @return A list of ticks.
1584:             */
1585:            protected List refreshTicksVertical(Graphics2D g2,
1586:                    Rectangle2D dataArea, RectangleEdge edge) {
1587:
1588:                List result = new java.util.ArrayList();
1589:
1590:                Font tickLabelFont = getTickLabelFont();
1591:                g2.setFont(tickLabelFont);
1592:
1593:                if (isAutoTickUnitSelection()) {
1594:                    selectAutoTickUnit(g2, dataArea, edge);
1595:                }
1596:                DateTickUnit unit = getTickUnit();
1597:                Date tickDate = calculateLowestVisibleTickValue(unit);
1598:                //Date upperDate = calculateHighestVisibleTickValue(unit);
1599:                Date upperDate = getMaximumDate();
1600:                while (tickDate.before(upperDate)) {
1601:
1602:                    if (!isHiddenValue(tickDate.getTime())) {
1603:                        // work out the value, label and position
1604:                        String tickLabel;
1605:                        DateFormat formatter = getDateFormatOverride();
1606:                        if (formatter != null) {
1607:                            tickLabel = formatter.format(tickDate);
1608:                        } else {
1609:                            tickLabel = this .tickUnit.dateToString(tickDate);
1610:                        }
1611:                        TextAnchor anchor = null;
1612:                        TextAnchor rotationAnchor = null;
1613:                        double angle = 0.0;
1614:                        if (isVerticalTickLabels()) {
1615:                            anchor = TextAnchor.BOTTOM_CENTER;
1616:                            rotationAnchor = TextAnchor.BOTTOM_CENTER;
1617:                            if (edge == RectangleEdge.LEFT) {
1618:                                angle = -Math.PI / 2.0;
1619:                            } else {
1620:                                angle = Math.PI / 2.0;
1621:                            }
1622:                        } else {
1623:                            if (edge == RectangleEdge.LEFT) {
1624:                                anchor = TextAnchor.CENTER_RIGHT;
1625:                                rotationAnchor = TextAnchor.CENTER_RIGHT;
1626:                            } else {
1627:                                anchor = TextAnchor.CENTER_LEFT;
1628:                                rotationAnchor = TextAnchor.CENTER_LEFT;
1629:                            }
1630:                        }
1631:
1632:                        Tick tick = new DateTick(tickDate, tickLabel, anchor,
1633:                                rotationAnchor, angle);
1634:                        result.add(tick);
1635:                        tickDate = unit.addToDate(tickDate, this .timeZone);
1636:                    } else {
1637:                        tickDate = unit.rollDate(tickDate, this .timeZone);
1638:                    }
1639:                }
1640:                return result;
1641:            }
1642:
1643:            /**
1644:             * Draws the axis on a Java 2D graphics device (such as the screen or a 
1645:             * printer).
1646:             *
1647:             * @param g2  the graphics device (<code>null</code> not permitted).
1648:             * @param cursor  the cursor location.
1649:             * @param plotArea  the area within which the axes and data should be 
1650:             *                  drawn (<code>null</code> not permitted).
1651:             * @param dataArea  the area within which the data should be drawn 
1652:             *                  (<code>null</code> not permitted).
1653:             * @param edge  the location of the axis (<code>null</code> not permitted).
1654:             * @param plotState  collects information about the plot 
1655:             *                   (<code>null</code> permitted).
1656:             *
1657:             * @return The axis state (never <code>null</code>).
1658:             */
1659:            public AxisState draw(Graphics2D g2, double cursor,
1660:                    Rectangle2D plotArea, Rectangle2D dataArea,
1661:                    RectangleEdge edge, PlotRenderingInfo plotState) {
1662:
1663:                // if the axis is not visible, don't draw it...
1664:                if (!isVisible()) {
1665:                    AxisState state = new AxisState(cursor);
1666:                    // even though the axis is not visible, we need to refresh ticks in
1667:                    // case the grid is being drawn...
1668:                    List ticks = refreshTicks(g2, state, dataArea, edge);
1669:                    state.setTicks(ticks);
1670:                    return state;
1671:                }
1672:
1673:                // draw the tick marks and labels...
1674:                AxisState state = drawTickMarksAndLabels(g2, cursor, plotArea,
1675:                        dataArea, edge);
1676:
1677:                // draw the axis label (note that 'state' is passed in *and* 
1678:                // returned)...
1679:                state = drawLabel(getLabel(), g2, plotArea, dataArea, edge,
1680:                        state);
1681:
1682:                return state;
1683:
1684:            }
1685:
1686:            /**
1687:             * Zooms in on the current range.
1688:             *
1689:             * @param lowerPercent  the new lower bound.
1690:             * @param upperPercent  the new upper bound.
1691:             */
1692:            public void zoomRange(double lowerPercent, double upperPercent) {
1693:                double start = this .timeline.toTimelineValue((long) getRange()
1694:                        .getLowerBound());
1695:                double length = (this .timeline
1696:                        .toTimelineValue((long) getRange().getUpperBound()) - this .timeline
1697:                        .toTimelineValue((long) getRange().getLowerBound()));
1698:                Range adjusted = null;
1699:                if (isInverted()) {
1700:                    adjusted = new DateRange(
1701:                            this .timeline
1702:                                    .toMillisecond((long) (start + (length * (1 - upperPercent)))),
1703:                            this .timeline
1704:                                    .toMillisecond((long) (start + (length * (1 - lowerPercent)))));
1705:                } else {
1706:                    adjusted = new DateRange(this .timeline
1707:                            .toMillisecond((long) (start + length
1708:                                    * lowerPercent)), this .timeline
1709:                            .toMillisecond((long) (start + length
1710:                                    * upperPercent)));
1711:                }
1712:                setRange(adjusted);
1713:            }
1714:
1715:            /**
1716:             * Tests this axis for equality with an arbitrary object.
1717:             *
1718:             * @param obj  the object (<code>null</code> permitted).
1719:             *
1720:             * @return A boolean.
1721:             */
1722:            public boolean equals(Object obj) {
1723:                if (obj == this ) {
1724:                    return true;
1725:                }
1726:                if (!(obj instanceof  DateAxis)) {
1727:                    return false;
1728:                }
1729:                DateAxis that = (DateAxis) obj;
1730:                if (!ObjectUtilities.equal(this .tickUnit, that.tickUnit)) {
1731:                    return false;
1732:                }
1733:                if (!ObjectUtilities.equal(this .dateFormatOverride,
1734:                        that.dateFormatOverride)) {
1735:                    return false;
1736:                }
1737:                if (!ObjectUtilities.equal(this .tickMarkPosition,
1738:                        that.tickMarkPosition)) {
1739:                    return false;
1740:                }
1741:                if (!ObjectUtilities.equal(this .timeline, that.timeline)) {
1742:                    return false;
1743:                }
1744:                if (!super .equals(obj)) {
1745:                    return false;
1746:                }
1747:                return true;
1748:            }
1749:
1750:            /**
1751:             * Returns a hash code for this object.
1752:             * 
1753:             * @return A hash code.
1754:             */
1755:            public int hashCode() {
1756:                if (getLabel() != null) {
1757:                    return getLabel().hashCode();
1758:                } else {
1759:                    return 0;
1760:                }
1761:            }
1762:
1763:            /**
1764:             * Returns a clone of the object.
1765:             *
1766:             * @return A clone.
1767:             *
1768:             * @throws CloneNotSupportedException if some component of the axis does 
1769:             *         not support cloning.
1770:             */
1771:            public Object clone() throws CloneNotSupportedException {
1772:
1773:                DateAxis clone = (DateAxis) super .clone();
1774:
1775:                // 'dateTickUnit' is immutable : no need to clone
1776:                if (this .dateFormatOverride != null) {
1777:                    clone.dateFormatOverride = (DateFormat) this .dateFormatOverride
1778:                            .clone();
1779:                }
1780:                // 'tickMarkPosition' is immutable : no need to clone
1781:
1782:                return clone;
1783:
1784:            }
1785:
1786:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.