Source Code Cross Referenced for ValueAxis.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:         * ValueAxis.java
0029:         * --------------
0030:         * (C) Copyright 2000-2007, by Object Refinery Limited and Contributors.
0031:         *
0032:         * Original Author:  David Gilbert (for Object Refinery Limited);
0033:         * Contributor(s):   Jonathan Nash;
0034:         *                   Nicolas Brodu (for Astrium and EADS Corporate Research 
0035:         *                   Center);
0036:         *
0037:         * $Id: ValueAxis.java,v 1.10.2.5 2007/03/22 12:13:27 mungady Exp $
0038:         *
0039:         * Changes (from 18-Sep-2001)
0040:         * --------------------------
0041:         * 18-Sep-2001 : Added standard header and fixed DOS encoding problem (DG);
0042:         * 23-Nov-2001 : Overhauled standard tick unit code (DG);
0043:         * 04-Dec-2001 : Changed constructors to protected, and tidied up default 
0044:         *               values (DG);
0045:         * 12-Dec-2001 : Fixed vertical gridlines bug (DG);
0046:         * 16-Jan-2002 : Added an optional crosshair, based on the implementation by 
0047:         *               Jonathan Nash (DG);
0048:         * 23-Jan-2002 : Moved the minimum and maximum values to here from NumberAxis, 
0049:         *               and changed the type from Number to double (DG);
0050:         * 25-Feb-2002 : Added default value for autoRange. Changed autoAdjustRange 
0051:         *               from public to protected. Updated import statements (DG);
0052:         * 23-Apr-2002 : Added setRange() method (DG);
0053:         * 29-Apr-2002 : Added range adjustment methods (DG);
0054:         * 13-Jun-2002 : Modified setCrosshairValue() to notify listeners only when the
0055:         *               crosshairs are visible, to avoid unnecessary repaints, as 
0056:         *               suggested by Kees Kuip (DG);
0057:         * 25-Jul-2002 : Moved lower and upper margin attributes from the NumberAxis 
0058:         *               class (DG);
0059:         * 05-Sep-2002 : Updated constructor for changes in Axis class (DG);
0060:         * 01-Oct-2002 : Fixed errors reported by Checkstyle (DG);
0061:         * 04-Oct-2002 : Moved standardTickUnits from NumberAxis --> ValueAxis (DG);
0062:         * 08-Nov-2002 : Moved to new package com.jrefinery.chart.axis (DG);
0063:         * 19-Nov-2002 : Removed grid settings (now controlled by the plot) (DG);
0064:         * 27-Nov-2002 : Moved the 'inverted' attributed from NumberAxis to 
0065:         *               ValueAxis (DG);
0066:         * 03-Jan-2003 : Small fix to ensure auto-range minimum is observed 
0067:         *               immediately (DG);
0068:         * 14-Jan-2003 : Changed autoRangeMinimumSize from Number --> double (DG);
0069:         * 20-Jan-2003 : Replaced monolithic constructor (DG);
0070:         * 26-Mar-2003 : Implemented Serializable (DG);
0071:         * 09-May-2003 : Added AxisLocation parameter to translation methods (DG);
0072:         * 13-Aug-2003 : Implemented Cloneable (DG);
0073:         * 01-Sep-2003 : Fixed bug 793167 (setMaximumAxisValue exception) (DG);
0074:         * 02-Sep-2003 : Fixed bug 795366 (zooming on inverted axes) (DG);
0075:         * 08-Sep-2003 : Completed Serialization support (NB);
0076:         * 08-Sep-2003 : Renamed get/setMinimumValue --> get/setLowerBound,
0077:         *               and get/setMaximumValue --> get/setUpperBound (DG);
0078:         * 27-Oct-2003 : Changed DEFAULT_AUTO_RANGE_MINIMUM_SIZE value - see bug ID 
0079:         *               829606 (DG);
0080:         * 07-Nov-2003 : Changes to tick mechanism (DG);
0081:         * 06-Jan-2004 : Moved axis line attributes to Axis class (DG);
0082:         * 21-Jan-2004 : Removed redundant axisLineVisible attribute.  Renamed 
0083:         *               translateJava2DToValue --> java2DToValue, and 
0084:         *               translateValueToJava2D --> valueToJava2D (DG); 
0085:         * 23-Jan-2004 : Fixed setAxisLinePaint() and setAxisLineStroke() which had no 
0086:         *               effect (andreas.gawecki@coremedia.com);
0087:         * 07-Apr-2004 : Changed text bounds calculation (DG);
0088:         * 26-Apr-2004 : Added getter/setter methods for arrow shapes (DG);
0089:         * 18-May-2004 : Added methods to set axis range *including* current 
0090:         *               margins (DG);
0091:         * 02-Jun-2004 : Fixed bug in setRangeWithMargins() method (DG);
0092:         * 30-Sep-2004 : Moved drawRotatedString() from RefineryUtilities 
0093:         *               --> TextUtilities (DG);
0094:         * 11-Jan-2005 : Removed deprecated methods in preparation for 1.0.0 
0095:         *               release (DG);
0096:         * 21-Apr-2005 : Replaced Insets with RectangleInsets (DG);
0097:         * ------------- JFREECHART 1.0.x ---------------------------------------------
0098:         * 10-Oct-2006 : Source reformatting (DG);
0099:         * 22-Mar-2007 : Added new defaultAutoRange attribute (DG);
0100:         *
0101:         */
0102:
0103:        package org.jfree.chart.axis;
0104:
0105:        import java.awt.Font;
0106:        import java.awt.FontMetrics;
0107:        import java.awt.Graphics2D;
0108:        import java.awt.Polygon;
0109:        import java.awt.Shape;
0110:        import java.awt.font.LineMetrics;
0111:        import java.awt.geom.AffineTransform;
0112:        import java.awt.geom.Line2D;
0113:        import java.awt.geom.Rectangle2D;
0114:        import java.io.IOException;
0115:        import java.io.ObjectInputStream;
0116:        import java.io.ObjectOutputStream;
0117:        import java.io.Serializable;
0118:        import java.util.Iterator;
0119:        import java.util.List;
0120:
0121:        import org.jfree.chart.event.AxisChangeEvent;
0122:        import org.jfree.chart.plot.Plot;
0123:        import org.jfree.data.Range;
0124:        import org.jfree.io.SerialUtilities;
0125:        import org.jfree.text.TextUtilities;
0126:        import org.jfree.ui.RectangleEdge;
0127:        import org.jfree.ui.RectangleInsets;
0128:        import org.jfree.util.ObjectUtilities;
0129:        import org.jfree.util.PublicCloneable;
0130:
0131:        /**
0132:         * The base class for axes that display value data, where values are measured 
0133:         * using the <code>double</code> primitive.  The two key subclasses are 
0134:         * {@link DateAxis} and {@link NumberAxis}.
0135:         */
0136:        public abstract class ValueAxis extends Axis implements  Cloneable,
0137:                PublicCloneable, Serializable {
0138:
0139:            /** For serialization. */
0140:            private static final long serialVersionUID = 3698345477322391456L;
0141:
0142:            /** The default axis range. */
0143:            public static final Range DEFAULT_RANGE = new Range(0.0, 1.0);
0144:
0145:            /** The default auto-range value. */
0146:            public static final boolean DEFAULT_AUTO_RANGE = true;
0147:
0148:            /** The default inverted flag setting. */
0149:            public static final boolean DEFAULT_INVERTED = false;
0150:
0151:            /** The default minimum auto range. */
0152:            public static final double DEFAULT_AUTO_RANGE_MINIMUM_SIZE = 0.00000001;
0153:
0154:            /** The default value for the lower margin (0.05 = 5%). */
0155:            public static final double DEFAULT_LOWER_MARGIN = 0.05;
0156:
0157:            /** The default value for the upper margin (0.05 = 5%). */
0158:            public static final double DEFAULT_UPPER_MARGIN = 0.05;
0159:
0160:            /** 
0161:             * The default lower bound for the axis.
0162:             * 
0163:             * @deprecated From 1.0.5 onwards, the axis defines a defaultRange 
0164:             *     attribute (see {@link #getDefaultAutoRange()}).
0165:             */
0166:            public static final double DEFAULT_LOWER_BOUND = 0.0;
0167:
0168:            /** 
0169:             * The default upper bound for the axis. 
0170:             * 
0171:             * @deprecated From 1.0.5 onwards, the axis defines a defaultRange 
0172:             *     attribute (see {@link #getDefaultAutoRange()}).
0173:             */
0174:            public static final double DEFAULT_UPPER_BOUND = 1.0;
0175:
0176:            /** The default auto-tick-unit-selection value. */
0177:            public static final boolean DEFAULT_AUTO_TICK_UNIT_SELECTION = true;
0178:
0179:            /** The maximum tick count. */
0180:            public static final int MAXIMUM_TICK_COUNT = 500;
0181:
0182:            /** 
0183:             * A flag that controls whether an arrow is drawn at the positive end of 
0184:             * the axis line. 
0185:             */
0186:            private boolean positiveArrowVisible;
0187:
0188:            /** 
0189:             * A flag that controls whether an arrow is drawn at the negative end of 
0190:             * the axis line. 
0191:             */
0192:            private boolean negativeArrowVisible;
0193:
0194:            /** The shape used for an up arrow. */
0195:            private transient Shape upArrow;
0196:
0197:            /** The shape used for a down arrow. */
0198:            private transient Shape downArrow;
0199:
0200:            /** The shape used for a left arrow. */
0201:            private transient Shape leftArrow;
0202:
0203:            /** The shape used for a right arrow. */
0204:            private transient Shape rightArrow;
0205:
0206:            /** A flag that affects the orientation of the values on the axis. */
0207:            private boolean inverted;
0208:
0209:            /** The axis range. */
0210:            private Range range;
0211:
0212:            /** 
0213:             * Flag that indicates whether the axis automatically scales to fit the 
0214:             * chart data. 
0215:             */
0216:            private boolean autoRange;
0217:
0218:            /** The minimum size for the 'auto' axis range (excluding margins). */
0219:            private double autoRangeMinimumSize;
0220:
0221:            /**
0222:             * The default range is used when the dataset is empty and the axis needs
0223:             * to determine the auto range.
0224:             * 
0225:             * @since 1.0.5
0226:             */
0227:            private Range defaultAutoRange;
0228:
0229:            /**
0230:             * The upper margin percentage.  This indicates the amount by which the 
0231:             * maximum axis value exceeds the maximum data value (as a percentage of 
0232:             * the range on the axis) when the axis range is determined automatically.
0233:             */
0234:            private double upperMargin;
0235:
0236:            /**
0237:             * The lower margin.  This is a percentage that indicates the amount by
0238:             * which the minimum axis value is "less than" the minimum data value when
0239:             * the axis range is determined automatically.
0240:             */
0241:            private double lowerMargin;
0242:
0243:            /**
0244:             * If this value is positive, the amount is subtracted from the maximum
0245:             * data value to determine the lower axis range.  This can be used to
0246:             * provide a fixed "window" on dynamic data.
0247:             */
0248:            private double fixedAutoRange;
0249:
0250:            /** 
0251:             * Flag that indicates whether or not the tick unit is selected 
0252:             * automatically. 
0253:             */
0254:            private boolean autoTickUnitSelection;
0255:
0256:            /** The standard tick units for the axis. */
0257:            private TickUnitSource standardTickUnits;
0258:
0259:            /** An index into an array of standard tick values. */
0260:            private int autoTickIndex;
0261:
0262:            /** A flag indicating whether or not tick labels are rotated to vertical. */
0263:            private boolean verticalTickLabels;
0264:
0265:            /**
0266:             * Constructs a value axis.
0267:             *
0268:             * @param label  the axis label (<code>null</code> permitted).
0269:             * @param standardTickUnits  the source for standard tick units 
0270:             *                           (<code>null</code> permitted).
0271:             */
0272:            protected ValueAxis(String label, TickUnitSource standardTickUnits) {
0273:
0274:                super (label);
0275:
0276:                this .positiveArrowVisible = false;
0277:                this .negativeArrowVisible = false;
0278:
0279:                this .range = DEFAULT_RANGE;
0280:                this .autoRange = DEFAULT_AUTO_RANGE;
0281:                this .defaultAutoRange = DEFAULT_RANGE;
0282:
0283:                this .inverted = DEFAULT_INVERTED;
0284:                this .autoRangeMinimumSize = DEFAULT_AUTO_RANGE_MINIMUM_SIZE;
0285:
0286:                this .lowerMargin = DEFAULT_LOWER_MARGIN;
0287:                this .upperMargin = DEFAULT_UPPER_MARGIN;
0288:
0289:                this .fixedAutoRange = 0.0;
0290:
0291:                this .autoTickUnitSelection = DEFAULT_AUTO_TICK_UNIT_SELECTION;
0292:                this .standardTickUnits = standardTickUnits;
0293:
0294:                Polygon p1 = new Polygon();
0295:                p1.addPoint(0, 0);
0296:                p1.addPoint(-2, 2);
0297:                p1.addPoint(2, 2);
0298:
0299:                this .upArrow = p1;
0300:
0301:                Polygon p2 = new Polygon();
0302:                p2.addPoint(0, 0);
0303:                p2.addPoint(-2, -2);
0304:                p2.addPoint(2, -2);
0305:
0306:                this .downArrow = p2;
0307:
0308:                Polygon p3 = new Polygon();
0309:                p3.addPoint(0, 0);
0310:                p3.addPoint(-2, -2);
0311:                p3.addPoint(-2, 2);
0312:
0313:                this .rightArrow = p3;
0314:
0315:                Polygon p4 = new Polygon();
0316:                p4.addPoint(0, 0);
0317:                p4.addPoint(2, -2);
0318:                p4.addPoint(2, 2);
0319:
0320:                this .leftArrow = p4;
0321:
0322:                this .verticalTickLabels = false;
0323:
0324:            }
0325:
0326:            /**
0327:             * Returns <code>true</code> if the tick labels should be rotated (to 
0328:             * vertical), and <code>false</code> otherwise.
0329:             *
0330:             * @return <code>true</code> or <code>false</code>.
0331:             * 
0332:             * @see #setVerticalTickLabels(boolean)
0333:             */
0334:            public boolean isVerticalTickLabels() {
0335:                return this .verticalTickLabels;
0336:            }
0337:
0338:            /**
0339:             * Sets the flag that controls whether the tick labels are displayed 
0340:             * vertically (that is, rotated 90 degrees from horizontal).  If the flag 
0341:             * is changed, an {@link AxisChangeEvent} is sent to all registered 
0342:             * listeners.
0343:             *
0344:             * @param flag  the flag.
0345:             * 
0346:             * @see #isVerticalTickLabels()
0347:             */
0348:            public void setVerticalTickLabels(boolean flag) {
0349:                if (this .verticalTickLabels != flag) {
0350:                    this .verticalTickLabels = flag;
0351:                    notifyListeners(new AxisChangeEvent(this ));
0352:                }
0353:            }
0354:
0355:            /**
0356:             * Returns a flag that controls whether or not the axis line has an arrow 
0357:             * drawn that points in the positive direction for the axis.
0358:             * 
0359:             * @return A boolean.
0360:             * 
0361:             * @see #setPositiveArrowVisible(boolean)
0362:             */
0363:            public boolean isPositiveArrowVisible() {
0364:                return this .positiveArrowVisible;
0365:            }
0366:
0367:            /**
0368:             * Sets a flag that controls whether or not the axis lines has an arrow 
0369:             * drawn that points in the positive direction for the axis, and sends an 
0370:             * {@link AxisChangeEvent} to all registered listeners.
0371:             * 
0372:             * @param visible  the flag.
0373:             * 
0374:             * @see #isPositiveArrowVisible()
0375:             */
0376:            public void setPositiveArrowVisible(boolean visible) {
0377:                this .positiveArrowVisible = visible;
0378:                notifyListeners(new AxisChangeEvent(this ));
0379:            }
0380:
0381:            /**
0382:             * Returns a flag that controls whether or not the axis line has an arrow 
0383:             * drawn that points in the negative direction for the axis.
0384:             * 
0385:             * @return A boolean.
0386:             * 
0387:             * @see #setNegativeArrowVisible(boolean)
0388:             */
0389:            public boolean isNegativeArrowVisible() {
0390:                return this .negativeArrowVisible;
0391:            }
0392:
0393:            /**
0394:             * Sets a flag that controls whether or not the axis lines has an arrow 
0395:             * drawn that points in the negative direction for the axis, and sends an 
0396:             * {@link AxisChangeEvent} to all registered listeners.
0397:             * 
0398:             * @param visible  the flag.
0399:             * 
0400:             * @see #setNegativeArrowVisible(boolean)
0401:             */
0402:            public void setNegativeArrowVisible(boolean visible) {
0403:                this .negativeArrowVisible = visible;
0404:                notifyListeners(new AxisChangeEvent(this ));
0405:            }
0406:
0407:            /**
0408:             * Returns a shape that can be displayed as an arrow pointing upwards at 
0409:             * the end of an axis line.
0410:             * 
0411:             * @return A shape (never <code>null</code>).
0412:             * 
0413:             * @see #setUpArrow(Shape)
0414:             */
0415:            public Shape getUpArrow() {
0416:                return this .upArrow;
0417:            }
0418:
0419:            /**
0420:             * Sets the shape that can be displayed as an arrow pointing upwards at 
0421:             * the end of an axis line and sends an {@link AxisChangeEvent} to all 
0422:             * registered listeners.
0423:             * 
0424:             * @param arrow  the arrow shape (<code>null</code> not permitted).
0425:             * 
0426:             * @see #getUpArrow()
0427:             */
0428:            public void setUpArrow(Shape arrow) {
0429:                if (arrow == null) {
0430:                    throw new IllegalArgumentException("Null 'arrow' argument.");
0431:                }
0432:                this .upArrow = arrow;
0433:                notifyListeners(new AxisChangeEvent(this ));
0434:            }
0435:
0436:            /**
0437:             * Returns a shape that can be displayed as an arrow pointing downwards at 
0438:             * the end of an axis line.
0439:             * 
0440:             * @return A shape (never <code>null</code>).
0441:             * 
0442:             * @see #setDownArrow(Shape)
0443:             */
0444:            public Shape getDownArrow() {
0445:                return this .downArrow;
0446:            }
0447:
0448:            /**
0449:             * Sets the shape that can be displayed as an arrow pointing downwards at 
0450:             * the end of an axis line and sends an {@link AxisChangeEvent} to all 
0451:             * registered listeners.
0452:             * 
0453:             * @param arrow  the arrow shape (<code>null</code> not permitted).
0454:             * 
0455:             * @see #getDownArrow()
0456:             */
0457:            public void setDownArrow(Shape arrow) {
0458:                if (arrow == null) {
0459:                    throw new IllegalArgumentException("Null 'arrow' argument.");
0460:                }
0461:                this .downArrow = arrow;
0462:                notifyListeners(new AxisChangeEvent(this ));
0463:            }
0464:
0465:            /**
0466:             * Returns a shape that can be displayed as an arrow pointing left at the 
0467:             * end of an axis line.
0468:             * 
0469:             * @return A shape (never <code>null</code>).
0470:             * 
0471:             * @see #setLeftArrow(Shape)
0472:             */
0473:            public Shape getLeftArrow() {
0474:                return this .leftArrow;
0475:            }
0476:
0477:            /**
0478:             * Sets the shape that can be displayed as an arrow pointing left at the 
0479:             * end of an axis line and sends an {@link AxisChangeEvent} to all 
0480:             * registered listeners.
0481:             * 
0482:             * @param arrow  the arrow shape (<code>null</code> not permitted).
0483:             * 
0484:             * @see #getLeftArrow()
0485:             */
0486:            public void setLeftArrow(Shape arrow) {
0487:                if (arrow == null) {
0488:                    throw new IllegalArgumentException("Null 'arrow' argument.");
0489:                }
0490:                this .leftArrow = arrow;
0491:                notifyListeners(new AxisChangeEvent(this ));
0492:            }
0493:
0494:            /**
0495:             * Returns a shape that can be displayed as an arrow pointing right at the 
0496:             * end of an axis line.
0497:             * 
0498:             * @return A shape (never <code>null</code>).
0499:             * 
0500:             * @see #setRightArrow(Shape)
0501:             */
0502:            public Shape getRightArrow() {
0503:                return this .rightArrow;
0504:            }
0505:
0506:            /**
0507:             * Sets the shape that can be displayed as an arrow pointing rightwards at 
0508:             * the end of an axis line and sends an {@link AxisChangeEvent} to all 
0509:             * registered listeners.
0510:             * 
0511:             * @param arrow  the arrow shape (<code>null</code> not permitted).
0512:             * 
0513:             * @see #getRightArrow()
0514:             */
0515:            public void setRightArrow(Shape arrow) {
0516:                if (arrow == null) {
0517:                    throw new IllegalArgumentException("Null 'arrow' argument.");
0518:                }
0519:                this .rightArrow = arrow;
0520:                notifyListeners(new AxisChangeEvent(this ));
0521:            }
0522:
0523:            /**
0524:             * Draws an axis line at the current cursor position and edge.
0525:             * 
0526:             * @param g2  the graphics device.
0527:             * @param cursor  the cursor position.
0528:             * @param dataArea  the data area.
0529:             * @param edge  the edge.
0530:             */
0531:            protected void drawAxisLine(Graphics2D g2, double cursor,
0532:                    Rectangle2D dataArea, RectangleEdge edge) {
0533:                Line2D axisLine = null;
0534:                if (edge == RectangleEdge.TOP) {
0535:                    axisLine = new Line2D.Double(dataArea.getX(), cursor,
0536:                            dataArea.getMaxX(), cursor);
0537:                } else if (edge == RectangleEdge.BOTTOM) {
0538:                    axisLine = new Line2D.Double(dataArea.getX(), cursor,
0539:                            dataArea.getMaxX(), cursor);
0540:                } else if (edge == RectangleEdge.LEFT) {
0541:                    axisLine = new Line2D.Double(cursor, dataArea.getY(),
0542:                            cursor, dataArea.getMaxY());
0543:                } else if (edge == RectangleEdge.RIGHT) {
0544:                    axisLine = new Line2D.Double(cursor, dataArea.getY(),
0545:                            cursor, dataArea.getMaxY());
0546:                }
0547:                g2.setPaint(getAxisLinePaint());
0548:                g2.setStroke(getAxisLineStroke());
0549:                g2.draw(axisLine);
0550:
0551:                boolean drawUpOrRight = false;
0552:                boolean drawDownOrLeft = false;
0553:                if (this .positiveArrowVisible) {
0554:                    if (this .inverted) {
0555:                        drawDownOrLeft = true;
0556:                    } else {
0557:                        drawUpOrRight = true;
0558:                    }
0559:                }
0560:                if (this .negativeArrowVisible) {
0561:                    if (this .inverted) {
0562:                        drawUpOrRight = true;
0563:                    } else {
0564:                        drawDownOrLeft = true;
0565:                    }
0566:                }
0567:                if (drawUpOrRight) {
0568:                    double x = 0.0;
0569:                    double y = 0.0;
0570:                    Shape arrow = null;
0571:                    if (edge == RectangleEdge.TOP
0572:                            || edge == RectangleEdge.BOTTOM) {
0573:                        x = dataArea.getMaxX();
0574:                        y = cursor;
0575:                        arrow = this .rightArrow;
0576:                    } else if (edge == RectangleEdge.LEFT
0577:                            || edge == RectangleEdge.RIGHT) {
0578:                        x = cursor;
0579:                        y = dataArea.getMinY();
0580:                        arrow = this .upArrow;
0581:                    }
0582:
0583:                    // draw the arrow...
0584:                    AffineTransform transformer = new AffineTransform();
0585:                    transformer.setToTranslation(x, y);
0586:                    Shape shape = transformer.createTransformedShape(arrow);
0587:                    g2.fill(shape);
0588:                    g2.draw(shape);
0589:                }
0590:
0591:                if (drawDownOrLeft) {
0592:                    double x = 0.0;
0593:                    double y = 0.0;
0594:                    Shape arrow = null;
0595:                    if (edge == RectangleEdge.TOP
0596:                            || edge == RectangleEdge.BOTTOM) {
0597:                        x = dataArea.getMinX();
0598:                        y = cursor;
0599:                        arrow = this .leftArrow;
0600:                    } else if (edge == RectangleEdge.LEFT
0601:                            || edge == RectangleEdge.RIGHT) {
0602:                        x = cursor;
0603:                        y = dataArea.getMaxY();
0604:                        arrow = this .downArrow;
0605:                    }
0606:
0607:                    // draw the arrow...
0608:                    AffineTransform transformer = new AffineTransform();
0609:                    transformer.setToTranslation(x, y);
0610:                    Shape shape = transformer.createTransformedShape(arrow);
0611:                    g2.fill(shape);
0612:                    g2.draw(shape);
0613:                }
0614:
0615:            }
0616:
0617:            /**
0618:             * Calculates the anchor point for a tick label.
0619:             * 
0620:             * @param tick  the tick.
0621:             * @param cursor  the cursor.
0622:             * @param dataArea  the data area.
0623:             * @param edge  the edge on which the axis is drawn.
0624:             * 
0625:             * @return The x and y coordinates of the anchor point.
0626:             */
0627:            protected float[] calculateAnchorPoint(ValueTick tick,
0628:                    double cursor, Rectangle2D dataArea, RectangleEdge edge) {
0629:
0630:                RectangleInsets insets = getTickLabelInsets();
0631:                float[] result = new float[2];
0632:                if (edge == RectangleEdge.TOP) {
0633:                    result[0] = (float) valueToJava2D(tick.getValue(),
0634:                            dataArea, edge);
0635:                    result[1] = (float) (cursor - insets.getBottom() - 2.0);
0636:                } else if (edge == RectangleEdge.BOTTOM) {
0637:                    result[0] = (float) valueToJava2D(tick.getValue(),
0638:                            dataArea, edge);
0639:                    result[1] = (float) (cursor + insets.getTop() + 2.0);
0640:                } else if (edge == RectangleEdge.LEFT) {
0641:                    result[0] = (float) (cursor - insets.getLeft() - 2.0);
0642:                    result[1] = (float) valueToJava2D(tick.getValue(),
0643:                            dataArea, edge);
0644:                } else if (edge == RectangleEdge.RIGHT) {
0645:                    result[0] = (float) (cursor + insets.getRight() + 2.0);
0646:                    result[1] = (float) valueToJava2D(tick.getValue(),
0647:                            dataArea, edge);
0648:                }
0649:                return result;
0650:            }
0651:
0652:            /**
0653:             * Draws the axis line, tick marks and tick mark labels.
0654:             * 
0655:             * @param g2  the graphics device.
0656:             * @param cursor  the cursor.
0657:             * @param plotArea  the plot area.
0658:             * @param dataArea  the data area.
0659:             * @param edge  the edge that the axis is aligned with.
0660:             * 
0661:             * @return The width or height used to draw the axis.
0662:             */
0663:            protected AxisState drawTickMarksAndLabels(Graphics2D g2,
0664:                    double cursor, Rectangle2D plotArea, Rectangle2D dataArea,
0665:                    RectangleEdge edge) {
0666:
0667:                AxisState state = new AxisState(cursor);
0668:
0669:                if (isAxisLineVisible()) {
0670:                    drawAxisLine(g2, cursor, dataArea, edge);
0671:                }
0672:
0673:                double ol = getTickMarkOutsideLength();
0674:                double il = getTickMarkInsideLength();
0675:
0676:                List ticks = refreshTicks(g2, state, dataArea, edge);
0677:                state.setTicks(ticks);
0678:                g2.setFont(getTickLabelFont());
0679:                Iterator iterator = ticks.iterator();
0680:                while (iterator.hasNext()) {
0681:                    ValueTick tick = (ValueTick) iterator.next();
0682:                    if (isTickLabelsVisible()) {
0683:                        g2.setPaint(getTickLabelPaint());
0684:                        float[] anchorPoint = calculateAnchorPoint(tick,
0685:                                cursor, dataArea, edge);
0686:                        TextUtilities.drawRotatedString(tick.getText(), g2,
0687:                                anchorPoint[0], anchorPoint[1], tick
0688:                                        .getTextAnchor(), tick.getAngle(), tick
0689:                                        .getRotationAnchor());
0690:                    }
0691:
0692:                    if (isTickMarksVisible()) {
0693:                        float xx = (float) valueToJava2D(tick.getValue(),
0694:                                dataArea, edge);
0695:                        Line2D mark = null;
0696:                        g2.setStroke(getTickMarkStroke());
0697:                        g2.setPaint(getTickMarkPaint());
0698:                        if (edge == RectangleEdge.LEFT) {
0699:                            mark = new Line2D.Double(cursor - ol, xx, cursor
0700:                                    + il, xx);
0701:                        } else if (edge == RectangleEdge.RIGHT) {
0702:                            mark = new Line2D.Double(cursor + ol, xx, cursor
0703:                                    - il, xx);
0704:                        } else if (edge == RectangleEdge.TOP) {
0705:                            mark = new Line2D.Double(xx, cursor - ol, xx,
0706:                                    cursor + il);
0707:                        } else if (edge == RectangleEdge.BOTTOM) {
0708:                            mark = new Line2D.Double(xx, cursor + ol, xx,
0709:                                    cursor - il);
0710:                        }
0711:                        g2.draw(mark);
0712:                    }
0713:                }
0714:
0715:                // need to work out the space used by the tick labels...
0716:                // so we can update the cursor...
0717:                double used = 0.0;
0718:                if (isTickLabelsVisible()) {
0719:                    if (edge == RectangleEdge.LEFT) {
0720:                        used += findMaximumTickLabelWidth(ticks, g2, plotArea,
0721:                                isVerticalTickLabels());
0722:                        state.cursorLeft(used);
0723:                    } else if (edge == RectangleEdge.RIGHT) {
0724:                        used = findMaximumTickLabelWidth(ticks, g2, plotArea,
0725:                                isVerticalTickLabels());
0726:                        state.cursorRight(used);
0727:                    } else if (edge == RectangleEdge.TOP) {
0728:                        used = findMaximumTickLabelHeight(ticks, g2, plotArea,
0729:                                isVerticalTickLabels());
0730:                        state.cursorUp(used);
0731:                    } else if (edge == RectangleEdge.BOTTOM) {
0732:                        used = findMaximumTickLabelHeight(ticks, g2, plotArea,
0733:                                isVerticalTickLabels());
0734:                        state.cursorDown(used);
0735:                    }
0736:                }
0737:
0738:                return state;
0739:            }
0740:
0741:            /**
0742:             * Returns the space required to draw the axis.
0743:             *
0744:             * @param g2  the graphics device.
0745:             * @param plot  the plot that the axis belongs to.
0746:             * @param plotArea  the area within which the plot should be drawn.
0747:             * @param edge  the axis location.
0748:             * @param space  the space already reserved (for other axes).
0749:             *
0750:             * @return The space required to draw the axis (including pre-reserved 
0751:             *         space).
0752:             */
0753:            public AxisSpace reserveSpace(Graphics2D g2, Plot plot,
0754:                    Rectangle2D plotArea, RectangleEdge edge, AxisSpace space) {
0755:
0756:                // create a new space object if one wasn't supplied...
0757:                if (space == null) {
0758:                    space = new AxisSpace();
0759:                }
0760:
0761:                // if the axis is not visible, no additional space is required...
0762:                if (!isVisible()) {
0763:                    return space;
0764:                }
0765:
0766:                // if the axis has a fixed dimension, return it...
0767:                double dimension = getFixedDimension();
0768:                if (dimension > 0.0) {
0769:                    space.ensureAtLeast(dimension, edge);
0770:                }
0771:
0772:                // calculate the max size of the tick labels (if visible)...
0773:                double tickLabelHeight = 0.0;
0774:                double tickLabelWidth = 0.0;
0775:                if (isTickLabelsVisible()) {
0776:                    g2.setFont(getTickLabelFont());
0777:                    List ticks = refreshTicks(g2, new AxisState(), plotArea,
0778:                            edge);
0779:                    if (RectangleEdge.isTopOrBottom(edge)) {
0780:                        tickLabelHeight = findMaximumTickLabelHeight(ticks, g2,
0781:                                plotArea, isVerticalTickLabels());
0782:                    } else if (RectangleEdge.isLeftOrRight(edge)) {
0783:                        tickLabelWidth = findMaximumTickLabelWidth(ticks, g2,
0784:                                plotArea, isVerticalTickLabels());
0785:                    }
0786:                }
0787:
0788:                // get the axis label size and update the space object...
0789:                Rectangle2D labelEnclosure = getLabelEnclosure(g2, edge);
0790:                double labelHeight = 0.0;
0791:                double labelWidth = 0.0;
0792:                if (RectangleEdge.isTopOrBottom(edge)) {
0793:                    labelHeight = labelEnclosure.getHeight();
0794:                    space.add(labelHeight + tickLabelHeight, edge);
0795:                } else if (RectangleEdge.isLeftOrRight(edge)) {
0796:                    labelWidth = labelEnclosure.getWidth();
0797:                    space.add(labelWidth + tickLabelWidth, edge);
0798:                }
0799:
0800:                return space;
0801:
0802:            }
0803:
0804:            /**
0805:             * A utility method for determining the height of the tallest tick label.
0806:             *
0807:             * @param ticks  the ticks.
0808:             * @param g2  the graphics device.
0809:             * @param drawArea  the area within which the plot and axes should be drawn.
0810:             * @param vertical  a flag that indicates whether or not the tick labels 
0811:             *                  are 'vertical'.
0812:             *
0813:             * @return The height of the tallest tick label.
0814:             */
0815:            protected double findMaximumTickLabelHeight(List ticks,
0816:                    Graphics2D g2, Rectangle2D drawArea, boolean vertical) {
0817:
0818:                RectangleInsets insets = getTickLabelInsets();
0819:                Font font = getTickLabelFont();
0820:                double maxHeight = 0.0;
0821:                if (vertical) {
0822:                    FontMetrics fm = g2.getFontMetrics(font);
0823:                    Iterator iterator = ticks.iterator();
0824:                    while (iterator.hasNext()) {
0825:                        Tick tick = (Tick) iterator.next();
0826:                        Rectangle2D labelBounds = TextUtilities.getTextBounds(
0827:                                tick.getText(), g2, fm);
0828:                        if (labelBounds.getWidth() + insets.getTop()
0829:                                + insets.getBottom() > maxHeight) {
0830:                            maxHeight = labelBounds.getWidth()
0831:                                    + insets.getTop() + insets.getBottom();
0832:                        }
0833:                    }
0834:                } else {
0835:                    LineMetrics metrics = font.getLineMetrics("ABCxyz", g2
0836:                            .getFontRenderContext());
0837:                    maxHeight = metrics.getHeight() + insets.getTop()
0838:                            + insets.getBottom();
0839:                }
0840:                return maxHeight;
0841:
0842:            }
0843:
0844:            /**
0845:             * A utility method for determining the width of the widest tick label.
0846:             *
0847:             * @param ticks  the ticks.
0848:             * @param g2  the graphics device.
0849:             * @param drawArea  the area within which the plot and axes should be drawn.
0850:             * @param vertical  a flag that indicates whether or not the tick labels 
0851:             *                  are 'vertical'.
0852:             *
0853:             * @return The width of the tallest tick label.
0854:             */
0855:            protected double findMaximumTickLabelWidth(List ticks,
0856:                    Graphics2D g2, Rectangle2D drawArea, boolean vertical) {
0857:
0858:                RectangleInsets insets = getTickLabelInsets();
0859:                Font font = getTickLabelFont();
0860:                double maxWidth = 0.0;
0861:                if (!vertical) {
0862:                    FontMetrics fm = g2.getFontMetrics(font);
0863:                    Iterator iterator = ticks.iterator();
0864:                    while (iterator.hasNext()) {
0865:                        Tick tick = (Tick) iterator.next();
0866:                        Rectangle2D labelBounds = TextUtilities.getTextBounds(
0867:                                tick.getText(), g2, fm);
0868:                        if (labelBounds.getWidth() + insets.getLeft()
0869:                                + insets.getRight() > maxWidth) {
0870:                            maxWidth = labelBounds.getWidth()
0871:                                    + insets.getLeft() + insets.getRight();
0872:                        }
0873:                    }
0874:                } else {
0875:                    LineMetrics metrics = font.getLineMetrics("ABCxyz", g2
0876:                            .getFontRenderContext());
0877:                    maxWidth = metrics.getHeight() + insets.getTop()
0878:                            + insets.getBottom();
0879:                }
0880:                return maxWidth;
0881:
0882:            }
0883:
0884:            /**
0885:             * Returns a flag that controls the direction of values on the axis.
0886:             * <P>
0887:             * For a regular axis, values increase from left to right (for a horizontal
0888:             * axis) and bottom to top (for a vertical axis).  When the axis is
0889:             * 'inverted', the values increase in the opposite direction.
0890:             *
0891:             * @return The flag.
0892:             * 
0893:             * @see #setInverted(boolean)
0894:             */
0895:            public boolean isInverted() {
0896:                return this .inverted;
0897:            }
0898:
0899:            /**
0900:             * Sets a flag that controls the direction of values on the axis, and
0901:             * notifies registered listeners that the axis has changed.
0902:             *
0903:             * @param flag  the flag.
0904:             * 
0905:             * @see #isInverted()
0906:             */
0907:            public void setInverted(boolean flag) {
0908:
0909:                if (this .inverted != flag) {
0910:                    this .inverted = flag;
0911:                    notifyListeners(new AxisChangeEvent(this ));
0912:                }
0913:
0914:            }
0915:
0916:            /**
0917:             * Returns the flag that controls whether or not the axis range is 
0918:             * automatically adjusted to fit the data values.
0919:             *
0920:             * @return The flag.
0921:             * 
0922:             * @see #setAutoRange(boolean)
0923:             */
0924:            public boolean isAutoRange() {
0925:                return this .autoRange;
0926:            }
0927:
0928:            /**
0929:             * Sets a flag that determines whether or not the axis range is
0930:             * automatically adjusted to fit the data, and notifies registered
0931:             * listeners that the axis has been modified.
0932:             *
0933:             * @param auto  the new value of the flag.
0934:             * 
0935:             * @see #isAutoRange()
0936:             */
0937:            public void setAutoRange(boolean auto) {
0938:                setAutoRange(auto, true);
0939:            }
0940:
0941:            /**
0942:             * Sets the auto range attribute.  If the <code>notify</code> flag is set, 
0943:             * an {@link AxisChangeEvent} is sent to registered listeners.
0944:             *
0945:             * @param auto  the flag.
0946:             * @param notify  notify listeners?
0947:             * 
0948:             * @see #isAutoRange()
0949:             */
0950:            protected void setAutoRange(boolean auto, boolean notify) {
0951:                if (this .autoRange != auto) {
0952:                    this .autoRange = auto;
0953:                    if (this .autoRange) {
0954:                        autoAdjustRange();
0955:                    }
0956:                    if (notify) {
0957:                        notifyListeners(new AxisChangeEvent(this ));
0958:                    }
0959:                }
0960:            }
0961:
0962:            /**
0963:             * Returns the minimum size allowed for the axis range when it is 
0964:             * automatically calculated.
0965:             *
0966:             * @return The minimum range.
0967:             * 
0968:             * @see #setAutoRangeMinimumSize(double)
0969:             */
0970:            public double getAutoRangeMinimumSize() {
0971:                return this .autoRangeMinimumSize;
0972:            }
0973:
0974:            /**
0975:             * Sets the auto range minimum size and sends an {@link AxisChangeEvent} 
0976:             * to all registered listeners.
0977:             *
0978:             * @param size  the size.
0979:             * 
0980:             * @see #getAutoRangeMinimumSize()
0981:             */
0982:            public void setAutoRangeMinimumSize(double size) {
0983:                setAutoRangeMinimumSize(size, true);
0984:            }
0985:
0986:            /**
0987:             * Sets the minimum size allowed for the axis range when it is 
0988:             * automatically calculated.
0989:             * <p>
0990:             * If requested, an {@link AxisChangeEvent} is forwarded to all registered 
0991:             * listeners.
0992:             *
0993:             * @param size  the new minimum.
0994:             * @param notify  notify listeners?
0995:             */
0996:            public void setAutoRangeMinimumSize(double size, boolean notify) {
0997:                if (size <= 0.0) {
0998:                    throw new IllegalArgumentException(
0999:                            "NumberAxis.setAutoRangeMinimumSize(double): must be > 0.0.");
1000:                }
1001:                if (this .autoRangeMinimumSize != size) {
1002:                    this .autoRangeMinimumSize = size;
1003:                    if (this .autoRange) {
1004:                        autoAdjustRange();
1005:                    }
1006:                    if (notify) {
1007:                        notifyListeners(new AxisChangeEvent(this ));
1008:                    }
1009:                }
1010:
1011:            }
1012:
1013:            /**
1014:             * Returns the default auto range.
1015:             * 
1016:             * @return The default auto range (never <code>null</code>).
1017:             * 
1018:             * @see #setDefaultAutoRange(Range)
1019:             * @since 1.0.5
1020:             */
1021:            public Range getDefaultAutoRange() {
1022:                return this .defaultAutoRange;
1023:            }
1024:
1025:            /**
1026:             * Sets the default auto range and sends an {@link AxisChangeEvent} to all
1027:             * registered listeners.
1028:             * 
1029:             * @param range  the range (<code>null</code> not permitted).
1030:             * 
1031:             * @see #getDefaultAutoRange()
1032:             * 
1033:             * @since 1.0.5
1034:             */
1035:            public void setDefaultAutoRange(Range range) {
1036:                if (range == null) {
1037:                    throw new IllegalArgumentException("Null 'range' argument.");
1038:                }
1039:                this .defaultAutoRange = range;
1040:                notifyListeners(new AxisChangeEvent(this ));
1041:            }
1042:
1043:            /**
1044:             * Returns the lower margin for the axis, expressed as a percentage of the 
1045:             * axis range.  This controls the space added to the lower end of the axis 
1046:             * when the axis range is automatically calculated (it is ignored when the 
1047:             * axis range is set explicitly). The default value is 0.05 (five percent).
1048:             *
1049:             * @return The lower margin.
1050:             *
1051:             * @see #setLowerMargin(double)
1052:             */
1053:            public double getLowerMargin() {
1054:                return this .lowerMargin;
1055:            }
1056:
1057:            /**
1058:             * Sets the lower margin for the axis (as a percentage of the axis range) 
1059:             * and sends an {@link AxisChangeEvent} to all registered listeners.  This
1060:             * margin is added only when the axis range is auto-calculated - if you set 
1061:             * the axis range manually, the margin is ignored.
1062:             *
1063:             * @param margin  the margin percentage (for example, 0.05 is five percent).
1064:             *
1065:             * @see #getLowerMargin()
1066:             * @see #setUpperMargin(double)
1067:             */
1068:            public void setLowerMargin(double margin) {
1069:                this .lowerMargin = margin;
1070:                if (isAutoRange()) {
1071:                    autoAdjustRange();
1072:                }
1073:                notifyListeners(new AxisChangeEvent(this ));
1074:            }
1075:
1076:            /**
1077:             * Returns the upper margin for the axis, expressed as a percentage of the 
1078:             * axis range.  This controls the space added to the lower end of the axis 
1079:             * when the axis range is automatically calculated (it is ignored when the 
1080:             * axis range is set explicitly). The default value is 0.05 (five percent).
1081:             *
1082:             * @return The upper margin.
1083:             *
1084:             * @see #setUpperMargin(double)
1085:             */
1086:            public double getUpperMargin() {
1087:                return this .upperMargin;
1088:            }
1089:
1090:            /**
1091:             * Sets the upper margin for the axis (as a percentage of the axis range) 
1092:             * and sends an {@link AxisChangeEvent} to all registered listeners.  This 
1093:             * margin is added only when the axis range is auto-calculated - if you set
1094:             * the axis range manually, the margin is ignored.
1095:             *
1096:             * @param margin  the margin percentage (for example, 0.05 is five percent).
1097:             *
1098:             * @see #getLowerMargin()
1099:             * @see #setLowerMargin(double)
1100:             */
1101:            public void setUpperMargin(double margin) {
1102:                this .upperMargin = margin;
1103:                if (isAutoRange()) {
1104:                    autoAdjustRange();
1105:                }
1106:                notifyListeners(new AxisChangeEvent(this ));
1107:            }
1108:
1109:            /**
1110:             * Returns the fixed auto range.
1111:             *
1112:             * @return The length.
1113:             * 
1114:             * @see #setFixedAutoRange(double)
1115:             */
1116:            public double getFixedAutoRange() {
1117:                return this .fixedAutoRange;
1118:            }
1119:
1120:            /**
1121:             * Sets the fixed auto range for the axis.
1122:             *
1123:             * @param length  the range length.
1124:             * 
1125:             * @see #getFixedAutoRange()
1126:             */
1127:            public void setFixedAutoRange(double length) {
1128:                this .fixedAutoRange = length;
1129:                if (isAutoRange()) {
1130:                    autoAdjustRange();
1131:                }
1132:                notifyListeners(new AxisChangeEvent(this ));
1133:            }
1134:
1135:            /**
1136:             * Returns the lower bound of the axis range.
1137:             *
1138:             * @return The lower bound.
1139:             * 
1140:             * @see #setLowerBound(double)
1141:             */
1142:            public double getLowerBound() {
1143:                return this .range.getLowerBound();
1144:            }
1145:
1146:            /**
1147:             * Sets the lower bound for the axis range.  An {@link AxisChangeEvent} is 
1148:             * sent to all registered listeners.
1149:             *
1150:             * @param min  the new minimum.
1151:             * 
1152:             * @see #getLowerBound()
1153:             */
1154:            public void setLowerBound(double min) {
1155:                if (this .range.getUpperBound() > min) {
1156:                    setRange(new Range(min, this .range.getUpperBound()));
1157:                } else {
1158:                    setRange(new Range(min, min + 1.0));
1159:                }
1160:            }
1161:
1162:            /**
1163:             * Returns the upper bound for the axis range.
1164:             *
1165:             * @return The upper bound.
1166:             * 
1167:             * @see #setUpperBound(double)
1168:             */
1169:            public double getUpperBound() {
1170:                return this .range.getUpperBound();
1171:            }
1172:
1173:            /**
1174:             * Sets the upper bound for the axis range, and sends an 
1175:             * {@link AxisChangeEvent} to all registered listeners.
1176:             *
1177:             * @param max  the new maximum.
1178:             * 
1179:             * @see #getUpperBound()
1180:             */
1181:            public void setUpperBound(double max) {
1182:                if (this .range.getLowerBound() < max) {
1183:                    setRange(new Range(this .range.getLowerBound(), max));
1184:                } else {
1185:                    setRange(max - 1.0, max);
1186:                }
1187:            }
1188:
1189:            /**
1190:             * Returns the range for the axis.
1191:             *
1192:             * @return The axis range (never <code>null</code>).
1193:             * 
1194:             * @see #setRange(Range)
1195:             */
1196:            public Range getRange() {
1197:                return this .range;
1198:            }
1199:
1200:            /**
1201:             * Sets the range attribute and sends an {@link AxisChangeEvent} to all 
1202:             * registered listeners.  As a side-effect, the auto-range flag is set to 
1203:             * <code>false</code>.
1204:             *
1205:             * @param range  the range (<code>null</code> not permitted).
1206:             * 
1207:             * @see #getRange()
1208:             */
1209:            public void setRange(Range range) {
1210:                // defer argument checking
1211:                setRange(range, true, true);
1212:            }
1213:
1214:            /**
1215:             * Sets the range for the axis, if requested, sends an 
1216:             * {@link AxisChangeEvent} to all registered listeners.  As a side-effect, 
1217:             * the auto-range flag is set to <code>false</code> (optional).
1218:             *
1219:             * @param range  the range (<code>null</code> not permitted).
1220:             * @param turnOffAutoRange  a flag that controls whether or not the auto 
1221:             *                          range is turned off.         
1222:             * @param notify  a flag that controls whether or not listeners are 
1223:             *                notified.
1224:             *                
1225:             * @see #getRange()
1226:             */
1227:            public void setRange(Range range, boolean turnOffAutoRange,
1228:                    boolean notify) {
1229:                if (range == null) {
1230:                    throw new IllegalArgumentException("Null 'range' argument.");
1231:                }
1232:                if (turnOffAutoRange) {
1233:                    this .autoRange = false;
1234:                }
1235:                this .range = range;
1236:                if (notify) {
1237:                    notifyListeners(new AxisChangeEvent(this ));
1238:                }
1239:            }
1240:
1241:            /**
1242:             * Sets the axis range and sends an {@link AxisChangeEvent} to all 
1243:             * registered listeners.  As a side-effect, the auto-range flag is set to 
1244:             * <code>false</code>.
1245:             *
1246:             * @param lower  the lower axis limit.
1247:             * @param upper  the upper axis limit.
1248:             * 
1249:             * @see #getRange()
1250:             * @see #setRange(Range)
1251:             */
1252:            public void setRange(double lower, double upper) {
1253:                setRange(new Range(lower, upper));
1254:            }
1255:
1256:            /**
1257:             * Sets the range for the axis (after first adding the current margins to 
1258:             * the specified range) and sends an {@link AxisChangeEvent} to all 
1259:             * registered listeners.
1260:             * 
1261:             * @param range  the range (<code>null</code> not permitted).
1262:             */
1263:            public void setRangeWithMargins(Range range) {
1264:                setRangeWithMargins(range, true, true);
1265:            }
1266:
1267:            /**
1268:             * Sets the range for the axis after first adding the current margins to 
1269:             * the range and, if requested, sends an {@link AxisChangeEvent} to all 
1270:             * registered listeners.  As a side-effect, the auto-range flag is set to 
1271:             * <code>false</code> (optional).
1272:             *
1273:             * @param range  the range (excluding margins, <code>null</code> not 
1274:             *               permitted).
1275:             * @param turnOffAutoRange  a flag that controls whether or not the auto 
1276:             *                          range is turned off.
1277:             * @param notify  a flag that controls whether or not listeners are 
1278:             *                notified.
1279:             */
1280:            public void setRangeWithMargins(Range range,
1281:                    boolean turnOffAutoRange, boolean notify) {
1282:                if (range == null) {
1283:                    throw new IllegalArgumentException("Null 'range' argument.");
1284:                }
1285:                setRange(Range
1286:                        .expand(range, getLowerMargin(), getUpperMargin()),
1287:                        turnOffAutoRange, notify);
1288:            }
1289:
1290:            /**
1291:             * Sets the axis range (after first adding the current margins to the 
1292:             * range) and sends an {@link AxisChangeEvent} to all registered listeners.
1293:             * As a side-effect, the auto-range flag is set to <code>false</code>.
1294:             *
1295:             * @param lower  the lower axis limit.
1296:             * @param upper  the upper axis limit.
1297:             */
1298:            public void setRangeWithMargins(double lower, double upper) {
1299:                setRangeWithMargins(new Range(lower, upper));
1300:            }
1301:
1302:            /**
1303:             * Sets the axis range, where the new range is 'size' in length, and 
1304:             * centered on 'value'.
1305:             *
1306:             * @param value  the central value.
1307:             * @param length  the range length.
1308:             */
1309:            public void setRangeAboutValue(double value, double length) {
1310:                setRange(new Range(value - length / 2, value + length / 2));
1311:            }
1312:
1313:            /**
1314:             * Returns a flag indicating whether or not the tick unit is automatically
1315:             * selected from a range of standard tick units.
1316:             *
1317:             * @return A flag indicating whether or not the tick unit is automatically
1318:             *         selected.
1319:             *         
1320:             * @see #setAutoTickUnitSelection(boolean)
1321:             */
1322:            public boolean isAutoTickUnitSelection() {
1323:                return this .autoTickUnitSelection;
1324:            }
1325:
1326:            /**
1327:             * Sets a flag indicating whether or not the tick unit is automatically
1328:             * selected from a range of standard tick units.  If the flag is changed, 
1329:             * registered listeners are notified that the chart has changed.
1330:             *
1331:             * @param flag  the new value of the flag.
1332:             * 
1333:             * @see #isAutoTickUnitSelection()
1334:             */
1335:            public void setAutoTickUnitSelection(boolean flag) {
1336:                setAutoTickUnitSelection(flag, true);
1337:            }
1338:
1339:            /**
1340:             * Sets a flag indicating whether or not the tick unit is automatically
1341:             * selected from a range of standard tick units.
1342:             *
1343:             * @param flag  the new value of the flag.
1344:             * @param notify  notify listeners?
1345:             * 
1346:             * @see #isAutoTickUnitSelection()
1347:             */
1348:            public void setAutoTickUnitSelection(boolean flag, boolean notify) {
1349:
1350:                if (this .autoTickUnitSelection != flag) {
1351:                    this .autoTickUnitSelection = flag;
1352:                    if (notify) {
1353:                        notifyListeners(new AxisChangeEvent(this ));
1354:                    }
1355:                }
1356:            }
1357:
1358:            /**
1359:             * Returns the source for obtaining standard tick units for the axis.
1360:             *
1361:             * @return The source (possibly <code>null</code>).
1362:             * 
1363:             * @see #setStandardTickUnits(TickUnitSource)
1364:             */
1365:            public TickUnitSource getStandardTickUnits() {
1366:                return this .standardTickUnits;
1367:            }
1368:
1369:            /**
1370:             * Sets the source for obtaining standard tick units for the axis and sends
1371:             * an {@link AxisChangeEvent} to all registered listeners.  The axis will 
1372:             * try to select the smallest tick unit from the source that does not cause
1373:             * the tick labels to overlap (see also the 
1374:             * {@link #setAutoTickUnitSelection(boolean)} method.
1375:             *
1376:             * @param source  the source for standard tick units (<code>null</code> 
1377:             *                permitted).
1378:             *                
1379:             * @see #getStandardTickUnits()
1380:             */
1381:            public void setStandardTickUnits(TickUnitSource source) {
1382:                this .standardTickUnits = source;
1383:                notifyListeners(new AxisChangeEvent(this ));
1384:            }
1385:
1386:            /**
1387:             * Converts a data value to a coordinate in Java2D space, assuming that the
1388:             * axis runs along one edge of the specified dataArea.
1389:             * <p>
1390:             * Note that it is possible for the coordinate to fall outside the area.
1391:             *
1392:             * @param value  the data value.
1393:             * @param area  the area for plotting the data.
1394:             * @param edge  the edge along which the axis lies.
1395:             *
1396:             * @return The Java2D coordinate.
1397:             * 
1398:             * @see #java2DToValue(double, Rectangle2D, RectangleEdge)
1399:             */
1400:            public abstract double valueToJava2D(double value,
1401:                    Rectangle2D area, RectangleEdge edge);
1402:
1403:            /**
1404:             * Converts a length in data coordinates into the corresponding length in 
1405:             * Java2D coordinates.
1406:             * 
1407:             * @param length  the length.
1408:             * @param area  the plot area.
1409:             * @param edge  the edge along which the axis lies.
1410:             * 
1411:             * @return The length in Java2D coordinates.
1412:             */
1413:            public double lengthToJava2D(double length, Rectangle2D area,
1414:                    RectangleEdge edge) {
1415:                double zero = valueToJava2D(0.0, area, edge);
1416:                double l = valueToJava2D(length, area, edge);
1417:                return Math.abs(l - zero);
1418:            }
1419:
1420:            /**
1421:             * Converts a coordinate in Java2D space to the corresponding data value,
1422:             * assuming that the axis runs along one edge of the specified dataArea.
1423:             *
1424:             * @param java2DValue  the coordinate in Java2D space.
1425:             * @param area  the area in which the data is plotted.
1426:             * @param edge  the edge along which the axis lies.
1427:             *
1428:             * @return The data value.
1429:             * 
1430:             * @see #valueToJava2D(double, Rectangle2D, RectangleEdge)
1431:             */
1432:            public abstract double java2DToValue(double java2DValue,
1433:                    Rectangle2D area, RectangleEdge edge);
1434:
1435:            /**
1436:             * Automatically sets the axis range to fit the range of values in the 
1437:             * dataset.  Sometimes this can depend on the renderer used as well (for 
1438:             * example, the renderer may "stack" values, requiring an axis range 
1439:             * greater than otherwise necessary).
1440:             */
1441:            protected abstract void autoAdjustRange();
1442:
1443:            /**
1444:             * Centers the axis range about the specified value and sends an 
1445:             * {@link AxisChangeEvent} to all registered listeners.
1446:             *
1447:             * @param value  the center value.
1448:             */
1449:            public void centerRange(double value) {
1450:
1451:                double central = this .range.getCentralValue();
1452:                Range adjusted = new Range(this .range.getLowerBound() + value
1453:                        - central, this .range.getUpperBound() + value - central);
1454:                setRange(adjusted);
1455:
1456:            }
1457:
1458:            /**
1459:             * Increases or decreases the axis range by the specified percentage about 
1460:             * the central value and sends an {@link AxisChangeEvent} to all registered
1461:             * listeners.
1462:             * <P>
1463:             * To double the length of the axis range, use 200% (2.0).
1464:             * To halve the length of the axis range, use 50% (0.5).
1465:             *
1466:             * @param percent  the resize factor.
1467:             */
1468:            public void resizeRange(double percent) {
1469:                resizeRange(percent, this .range.getCentralValue());
1470:            }
1471:
1472:            /**
1473:             * Increases or decreases the axis range by the specified percentage about
1474:             * the specified anchor value and sends an {@link AxisChangeEvent} to all 
1475:             * registered listeners.
1476:             * <P>
1477:             * To double the length of the axis range, use 200% (2.0).
1478:             * To halve the length of the axis range, use 50% (0.5).
1479:             *
1480:             * @param percent  the resize factor.
1481:             * @param anchorValue  the new central value after the resize.
1482:             */
1483:            public void resizeRange(double percent, double anchorValue) {
1484:                if (percent > 0.0) {
1485:                    double halfLength = this .range.getLength() * percent / 2;
1486:                    Range adjusted = new Range(anchorValue - halfLength,
1487:                            anchorValue + halfLength);
1488:                    setRange(adjusted);
1489:                } else {
1490:                    setAutoRange(true);
1491:                }
1492:            }
1493:
1494:            /**
1495:             * Zooms in on the current range.
1496:             * 
1497:             * @param lowerPercent  the new lower bound.
1498:             * @param upperPercent  the new upper bound.
1499:             */
1500:            public void zoomRange(double lowerPercent, double upperPercent) {
1501:                double start = this .range.getLowerBound();
1502:                double length = this .range.getLength();
1503:                Range adjusted = null;
1504:                if (isInverted()) {
1505:                    adjusted = new Range(start + (length * (1 - upperPercent)),
1506:                            start + (length * (1 - lowerPercent)));
1507:                } else {
1508:                    adjusted = new Range(start + length * lowerPercent, start
1509:                            + length * upperPercent);
1510:                }
1511:                setRange(adjusted);
1512:            }
1513:
1514:            /**
1515:             * Returns the auto tick index.
1516:             *
1517:             * @return The auto tick index.
1518:             * 
1519:             * @see #setAutoTickIndex(int)
1520:             */
1521:            protected int getAutoTickIndex() {
1522:                return this .autoTickIndex;
1523:            }
1524:
1525:            /**
1526:             * Sets the auto tick index.
1527:             *
1528:             * @param index  the new value.
1529:             * 
1530:             * @see #getAutoTickIndex()
1531:             */
1532:            protected void setAutoTickIndex(int index) {
1533:                this .autoTickIndex = index;
1534:            }
1535:
1536:            /**
1537:             * Tests the axis for equality with an arbitrary object.
1538:             *
1539:             * @param obj  the object (<code>null</code> permitted).
1540:             *
1541:             * @return <code>true</code> or <code>false</code>.
1542:             */
1543:            public boolean equals(Object obj) {
1544:
1545:                if (obj == this ) {
1546:                    return true;
1547:                }
1548:                if (!(obj instanceof  ValueAxis)) {
1549:                    return false;
1550:                }
1551:
1552:                ValueAxis that = (ValueAxis) obj;
1553:
1554:                if (this .positiveArrowVisible != that.positiveArrowVisible) {
1555:                    return false;
1556:                }
1557:                if (this .negativeArrowVisible != that.negativeArrowVisible) {
1558:                    return false;
1559:                }
1560:                if (this .inverted != that.inverted) {
1561:                    return false;
1562:                }
1563:                if (!ObjectUtilities.equal(this .range, that.range)) {
1564:                    return false;
1565:                }
1566:                if (this .autoRange != that.autoRange) {
1567:                    return false;
1568:                }
1569:                if (this .autoRangeMinimumSize != that.autoRangeMinimumSize) {
1570:                    return false;
1571:                }
1572:                if (!this .defaultAutoRange.equals(that.defaultAutoRange)) {
1573:                    return false;
1574:                }
1575:                if (this .upperMargin != that.upperMargin) {
1576:                    return false;
1577:                }
1578:                if (this .lowerMargin != that.lowerMargin) {
1579:                    return false;
1580:                }
1581:                if (this .fixedAutoRange != that.fixedAutoRange) {
1582:                    return false;
1583:                }
1584:                if (this .autoTickUnitSelection != that.autoTickUnitSelection) {
1585:                    return false;
1586:                }
1587:                if (!ObjectUtilities.equal(this .standardTickUnits,
1588:                        that.standardTickUnits)) {
1589:                    return false;
1590:                }
1591:                if (this .verticalTickLabels != that.verticalTickLabels) {
1592:                    return false;
1593:                }
1594:
1595:                return super .equals(obj);
1596:
1597:            }
1598:
1599:            /**
1600:             * Returns a clone of the object.
1601:             * 
1602:             * @return A clone.
1603:             * 
1604:             * @throws CloneNotSupportedException if some component of the axis does 
1605:             *         not support cloning.
1606:             */
1607:            public Object clone() throws CloneNotSupportedException {
1608:                ValueAxis clone = (ValueAxis) super .clone();
1609:                return clone;
1610:            }
1611:
1612:            /**
1613:             * Provides serialization support.
1614:             *
1615:             * @param stream  the output stream.
1616:             *
1617:             * @throws IOException  if there is an I/O error.
1618:             */
1619:            private void writeObject(ObjectOutputStream stream)
1620:                    throws IOException {
1621:                stream.defaultWriteObject();
1622:                SerialUtilities.writeShape(this .upArrow, stream);
1623:                SerialUtilities.writeShape(this .downArrow, stream);
1624:                SerialUtilities.writeShape(this .leftArrow, stream);
1625:                SerialUtilities.writeShape(this .rightArrow, stream);
1626:            }
1627:
1628:            /**
1629:             * Provides serialization support.
1630:             *
1631:             * @param stream  the input stream.
1632:             *
1633:             * @throws IOException  if there is an I/O error.
1634:             * @throws ClassNotFoundException  if there is a classpath problem.
1635:             */
1636:            private void readObject(ObjectInputStream stream)
1637:                    throws IOException, ClassNotFoundException {
1638:
1639:                stream.defaultReadObject();
1640:                this.upArrow = SerialUtilities.readShape(stream);
1641:                this.downArrow = SerialUtilities.readShape(stream);
1642:                this.leftArrow = SerialUtilities.readShape(stream);
1643:                this.rightArrow = SerialUtilities.readShape(stream);
1644:
1645:            }
1646:
1647:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.