Source Code Cross Referenced for ThermometerPlot.java in  » Chart » jfreechart » org » jfree » chart » plot » 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.plot 
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:         * ThermometerPlot.java
0029:         * --------------------
0030:         *
0031:         * (C) Copyright 2000-2007, by Bryan Scott and Contributors.
0032:         *
0033:         * Original Author:  Bryan Scott (based on MeterPlot by Hari).
0034:         * Contributor(s):   David Gilbert (for Object Refinery Limited).
0035:         *                   Arnaud Lelievre;
0036:         *
0037:         * Changes
0038:         * -------
0039:         * 11-Apr-2002 : Version 1, contributed by Bryan Scott;
0040:         * 15-Apr-2002 : Changed to implement VerticalValuePlot;
0041:         * 29-Apr-2002 : Added getVerticalValueAxis() method (DG);
0042:         * 25-Jun-2002 : Removed redundant imports (DG);
0043:         * 17-Sep-2002 : Reviewed with Checkstyle utility (DG);
0044:         * 18-Sep-2002 : Extensive changes made to API, to iron out bugs and 
0045:         *               inconsistencies (DG);
0046:         * 13-Oct-2002 : Corrected error datasetChanged which would generate exceptions
0047:         *               when value set to null (BRS).
0048:         * 23-Jan-2003 : Removed one constructor (DG);
0049:         * 26-Mar-2003 : Implemented Serializable (DG);
0050:         * 02-Jun-2003 : Removed test for compatible range axis (DG);
0051:         * 01-Jul-2003 : Added additional check in draw method to ensure value not 
0052:         *               null (BRS);
0053:         * 08-Sep-2003 : Added internationalization via use of properties 
0054:         *               resourceBundle (RFE 690236) (AL);
0055:         * 16-Sep-2003 : Changed ChartRenderingInfo --> PlotRenderingInfo (DG);
0056:         * 29-Sep-2003 : Updated draw to set value of cursor to non-zero and allow 
0057:         *               painting of axis.  An incomplete fix and needs to be set for 
0058:         *               left or right drawing (BRS);
0059:         * 19-Nov-2003 : Added support for value labels to be displayed left of the 
0060:         *               thermometer
0061:         * 19-Nov-2003 : Improved axis drawing (now default axis does not draw axis line
0062:         *               and is closer to the bulb).  Added support for the positioning
0063:         *               of the axis to the left or right of the bulb. (BRS);
0064:         * 03-Dec-2003 : Directly mapped deprecated setData()/getData() method to 
0065:         *               get/setDataset() (TM);
0066:         * 21-Jan-2004 : Update for renamed method in ValueAxis (DG);
0067:         * 07-Apr-2004 : Changed string width calculation (DG);
0068:         * 12-Nov-2004 : Implemented the new Zoomable interface (DG);
0069:         * 06-Jan-2004 : Added getOrientation() method (DG);
0070:         * 11-Jan-2005 : Removed deprecated code in preparation for 1.0.0 release (DG);
0071:         * 29-Mar-2005 : Fixed equals() method (DG);
0072:         * 05-May-2005 : Updated draw() method parameters (DG);
0073:         * 09-Jun-2005 : Fixed more bugs in equals() method (DG);
0074:         * 10-Jun-2005 : Fixed minor bug in setDisplayRange() method (DG);
0075:         * ------------- JFREECHART 1.0.x ---------------------------------------------
0076:         * 14-Nov-2006 : Fixed margin when drawing (DG);
0077:         * 03-May-2007 : Fixed datasetChanged() to handle null dataset, added null 
0078:         *               argument check and event notification to setRangeAxis(), 
0079:         *               added null argument check to setPadding(), setValueFont(),
0080:         *               setValuePaint(), setValueFormat() and setMercuryPaint(), 
0081:         *               deprecated get/setShowValueLines(), deprecated 
0082:         *               getMinimum/MaximumVerticalDataValue(), and fixed serialization 
0083:         *               bug (DG);
0084:         * 
0085:         */
0086:
0087:        package org.jfree.chart.plot;
0088:
0089:        import java.awt.BasicStroke;
0090:        import java.awt.Color;
0091:        import java.awt.Font;
0092:        import java.awt.FontMetrics;
0093:        import java.awt.Graphics2D;
0094:        import java.awt.Paint;
0095:        import java.awt.Stroke;
0096:        import java.awt.geom.Area;
0097:        import java.awt.geom.Ellipse2D;
0098:        import java.awt.geom.Line2D;
0099:        import java.awt.geom.Point2D;
0100:        import java.awt.geom.Rectangle2D;
0101:        import java.awt.geom.RoundRectangle2D;
0102:        import java.io.IOException;
0103:        import java.io.ObjectInputStream;
0104:        import java.io.ObjectOutputStream;
0105:        import java.io.Serializable;
0106:        import java.text.DecimalFormat;
0107:        import java.text.NumberFormat;
0108:        import java.util.Arrays;
0109:        import java.util.ResourceBundle;
0110:
0111:        import org.jfree.chart.LegendItemCollection;
0112:        import org.jfree.chart.axis.NumberAxis;
0113:        import org.jfree.chart.axis.ValueAxis;
0114:        import org.jfree.chart.event.PlotChangeEvent;
0115:        import org.jfree.data.Range;
0116:        import org.jfree.data.general.DatasetChangeEvent;
0117:        import org.jfree.data.general.DefaultValueDataset;
0118:        import org.jfree.data.general.ValueDataset;
0119:        import org.jfree.io.SerialUtilities;
0120:        import org.jfree.ui.RectangleEdge;
0121:        import org.jfree.ui.RectangleInsets;
0122:        import org.jfree.util.ObjectUtilities;
0123:        import org.jfree.util.PaintUtilities;
0124:        import org.jfree.util.UnitType;
0125:
0126:        /**
0127:         * A plot that displays a single value (from a {@link ValueDataset}) in a 
0128:         * thermometer type display.
0129:         * <p>
0130:         * This plot supports a number of options:
0131:         * <ol>
0132:         * <li>three sub-ranges which could be viewed as 'Normal', 'Warning' 
0133:         *   and 'Critical' ranges.</li>
0134:         * <li>the thermometer can be run in two modes:
0135:         *      <ul>
0136:         *      <li>fixed range, or</li>
0137:         *      <li>range adjusts to current sub-range.</li>
0138:         *      </ul>
0139:         * </li>
0140:         * <li>settable units to be displayed.</li>
0141:         * <li>settable display location for the value text.</li>
0142:         * </ol>
0143:         */
0144:        public class ThermometerPlot extends Plot implements  ValueAxisPlot,
0145:                Zoomable, Cloneable, Serializable {
0146:
0147:            /** For serialization. */
0148:            private static final long serialVersionUID = 4087093313147984390L;
0149:
0150:            /** A constant for unit type 'None'. */
0151:            public static final int UNITS_NONE = 0;
0152:
0153:            /** A constant for unit type 'Fahrenheit'. */
0154:            public static final int UNITS_FAHRENHEIT = 1;
0155:
0156:            /** A constant for unit type 'Celcius'. */
0157:            public static final int UNITS_CELCIUS = 2;
0158:
0159:            /** A constant for unit type 'Kelvin'. */
0160:            public static final int UNITS_KELVIN = 3;
0161:
0162:            /** A constant for the value label position (no label). */
0163:            public static final int NONE = 0;
0164:
0165:            /** A constant for the value label position (right of the thermometer). */
0166:            public static final int RIGHT = 1;
0167:
0168:            /** A constant for the value label position (left of the thermometer). */
0169:            public static final int LEFT = 2;
0170:
0171:            /** A constant for the value label position (in the thermometer bulb). */
0172:            public static final int BULB = 3;
0173:
0174:            /** A constant for the 'normal' range. */
0175:            public static final int NORMAL = 0;
0176:
0177:            /** A constant for the 'warning' range. */
0178:            public static final int WARNING = 1;
0179:
0180:            /** A constant for the 'critical' range. */
0181:            public static final int CRITICAL = 2;
0182:
0183:            /** The bulb radius. */
0184:            protected static final int BULB_RADIUS = 40;
0185:
0186:            /** The bulb diameter. */
0187:            protected static final int BULB_DIAMETER = BULB_RADIUS * 2;
0188:
0189:            /** The column radius. */
0190:            protected static final int COLUMN_RADIUS = 20;
0191:
0192:            /** The column diameter.*/
0193:            protected static final int COLUMN_DIAMETER = COLUMN_RADIUS * 2;
0194:
0195:            /** The gap radius. */
0196:            protected static final int GAP_RADIUS = 5;
0197:
0198:            /** The gap diameter. */
0199:            protected static final int GAP_DIAMETER = GAP_RADIUS * 2;
0200:
0201:            /** The axis gap. */
0202:            protected static final int AXIS_GAP = 10;
0203:
0204:            /** The unit strings. */
0205:            protected static final String[] UNITS = { "", "\u00B0F", "\u00B0C",
0206:                    "\u00B0K" };
0207:
0208:            /** Index for low value in subrangeInfo matrix. */
0209:            protected static final int RANGE_LOW = 0;
0210:
0211:            /** Index for high value in subrangeInfo matrix. */
0212:            protected static final int RANGE_HIGH = 1;
0213:
0214:            /** Index for display low value in subrangeInfo matrix. */
0215:            protected static final int DISPLAY_LOW = 2;
0216:
0217:            /** Index for display high value in subrangeInfo matrix. */
0218:            protected static final int DISPLAY_HIGH = 3;
0219:
0220:            /** The default lower bound. */
0221:            protected static final double DEFAULT_LOWER_BOUND = 0.0;
0222:
0223:            /** The default upper bound. */
0224:            protected static final double DEFAULT_UPPER_BOUND = 100.0;
0225:
0226:            /** The dataset for the plot. */
0227:            private ValueDataset dataset;
0228:
0229:            /** The range axis. */
0230:            private ValueAxis rangeAxis;
0231:
0232:            /** The lower bound for the thermometer. */
0233:            private double lowerBound = DEFAULT_LOWER_BOUND;
0234:
0235:            /** The upper bound for the thermometer. */
0236:            private double upperBound = DEFAULT_UPPER_BOUND;
0237:
0238:            /** 
0239:             * Blank space inside the plot area around the outside of the thermometer. 
0240:             */
0241:            private RectangleInsets padding;
0242:
0243:            /** Stroke for drawing the thermometer */
0244:            private transient Stroke thermometerStroke = new BasicStroke(1.0f);
0245:
0246:            /** Paint for drawing the thermometer */
0247:            private transient Paint thermometerPaint = Color.black;
0248:
0249:            /** The display units */
0250:            private int units = UNITS_CELCIUS;
0251:
0252:            /** The value label position. */
0253:            private int valueLocation = BULB;
0254:
0255:            /** The position of the axis **/
0256:            private int axisLocation = LEFT;
0257:
0258:            /** The font to write the value in */
0259:            private Font valueFont = new Font("SansSerif", Font.BOLD, 16);
0260:
0261:            /** Colour that the value is written in */
0262:            private transient Paint valuePaint = Color.white;
0263:
0264:            /** Number format for the value */
0265:            private NumberFormat valueFormat = new DecimalFormat();
0266:
0267:            /** The default paint for the mercury in the thermometer. */
0268:            private transient Paint mercuryPaint = Color.lightGray;
0269:
0270:            /** A flag that controls whether value lines are drawn. */
0271:            private boolean showValueLines = false;
0272:
0273:            /** The display sub-range. */
0274:            private int subrange = -1;
0275:
0276:            /** The start and end values for the subranges. */
0277:            private double[][] subrangeInfo = { { 0.0, 50.0, 0.0, 50.0 },
0278:                    { 50.0, 75.0, 50.0, 75.0 }, { 75.0, 100.0, 75.0, 100.0 } };
0279:
0280:            /** 
0281:             * A flag that controls whether or not the axis range adjusts to the 
0282:             * sub-ranges. 
0283:             */
0284:            private boolean followDataInSubranges = false;
0285:
0286:            /** 
0287:             * A flag that controls whether or not the mercury paint changes with 
0288:             * the subranges. 
0289:             */
0290:            private boolean useSubrangePaint = true;
0291:
0292:            /** Paint for each range */
0293:            private transient Paint[] subrangePaint = { Color.green,
0294:                    Color.orange, Color.red };
0295:
0296:            /** A flag that controls whether the sub-range indicators are visible. */
0297:            private boolean subrangeIndicatorsVisible = true;
0298:
0299:            /** The stroke for the sub-range indicators. */
0300:            private transient Stroke subrangeIndicatorStroke = new BasicStroke(
0301:                    2.0f);
0302:
0303:            /** The range indicator stroke. */
0304:            private transient Stroke rangeIndicatorStroke = new BasicStroke(
0305:                    3.0f);
0306:
0307:            /** The resourceBundle for the localization. */
0308:            protected static ResourceBundle localizationResources = ResourceBundle
0309:                    .getBundle("org.jfree.chart.plot.LocalizationBundle");
0310:
0311:            /**
0312:             * Creates a new thermometer plot.
0313:             */
0314:            public ThermometerPlot() {
0315:                this (new DefaultValueDataset());
0316:            }
0317:
0318:            /**
0319:             * Creates a new thermometer plot, using default attributes where necessary.
0320:             *
0321:             * @param dataset  the data set.
0322:             */
0323:            public ThermometerPlot(ValueDataset dataset) {
0324:
0325:                super ();
0326:
0327:                this .padding = new RectangleInsets(UnitType.RELATIVE, 0.05,
0328:                        0.05, 0.05, 0.05);
0329:                this .dataset = dataset;
0330:                if (dataset != null) {
0331:                    dataset.addChangeListener(this );
0332:                }
0333:                NumberAxis axis = new NumberAxis(null);
0334:                axis.setStandardTickUnits(NumberAxis.createIntegerTickUnits());
0335:                axis.setAxisLineVisible(false);
0336:                axis.setPlot(this );
0337:                axis.addChangeListener(this );
0338:                this .rangeAxis = axis;
0339:                setAxisRange();
0340:            }
0341:
0342:            /**
0343:             * Returns the dataset for the plot.
0344:             *
0345:             * @return The dataset (possibly <code>null</code>).
0346:             * 
0347:             * @see #setDataset(ValueDataset)
0348:             */
0349:            public ValueDataset getDataset() {
0350:                return this .dataset;
0351:            }
0352:
0353:            /**
0354:             * Sets the dataset for the plot, replacing the existing dataset if there 
0355:             * is one, and sends a {@link PlotChangeEvent} to all registered listeners.
0356:             *
0357:             * @param dataset  the dataset (<code>null</code> permitted).
0358:             * 
0359:             * @see #getDataset()
0360:             */
0361:            public void setDataset(ValueDataset dataset) {
0362:
0363:                // if there is an existing dataset, remove the plot from the list 
0364:                // of change listeners...
0365:                ValueDataset existing = this .dataset;
0366:                if (existing != null) {
0367:                    existing.removeChangeListener(this );
0368:                }
0369:
0370:                // set the new dataset, and register the chart as a change listener...
0371:                this .dataset = dataset;
0372:                if (dataset != null) {
0373:                    setDatasetGroup(dataset.getGroup());
0374:                    dataset.addChangeListener(this );
0375:                }
0376:
0377:                // send a dataset change event to self...
0378:                DatasetChangeEvent event = new DatasetChangeEvent(this , dataset);
0379:                datasetChanged(event);
0380:
0381:            }
0382:
0383:            /**
0384:             * Returns the range axis.
0385:             *
0386:             * @return The range axis (never <code>null</code>).
0387:             * 
0388:             * @see #setRangeAxis(ValueAxis)
0389:             */
0390:            public ValueAxis getRangeAxis() {
0391:                return this .rangeAxis;
0392:            }
0393:
0394:            /**
0395:             * Sets the range axis for the plot and sends a {@link PlotChangeEvent} to 
0396:             * all registered listeners.
0397:             *
0398:             * @param axis  the new axis (<code>null</code> not permitted).
0399:             * 
0400:             * @see #getRangeAxis()
0401:             */
0402:            public void setRangeAxis(ValueAxis axis) {
0403:                if (axis == null) {
0404:                    throw new IllegalArgumentException("Null 'axis' argument.");
0405:                }
0406:                // plot is registered as a listener with the existing axis...
0407:                this .rangeAxis.removeChangeListener(this );
0408:
0409:                axis.setPlot(this );
0410:                axis.addChangeListener(this );
0411:                this .rangeAxis = axis;
0412:                notifyListeners(new PlotChangeEvent(this ));
0413:
0414:            }
0415:
0416:            /**
0417:             * Returns the lower bound for the thermometer.  The data value can be set 
0418:             * lower than this, but it will not be shown in the thermometer.
0419:             *
0420:             * @return The lower bound.
0421:             * 
0422:             * @see #setLowerBound(double)
0423:             */
0424:            public double getLowerBound() {
0425:                return this .lowerBound;
0426:            }
0427:
0428:            /**
0429:             * Sets the lower bound for the thermometer.
0430:             *
0431:             * @param lower the lower bound.
0432:             * 
0433:             * @see #getLowerBound()
0434:             */
0435:            public void setLowerBound(double lower) {
0436:                this .lowerBound = lower;
0437:                setAxisRange();
0438:            }
0439:
0440:            /**
0441:             * Returns the upper bound for the thermometer.  The data value can be set 
0442:             * higher than this, but it will not be shown in the thermometer.
0443:             *
0444:             * @return The upper bound.
0445:             * 
0446:             * @see #setUpperBound(double)
0447:             */
0448:            public double getUpperBound() {
0449:                return this .upperBound;
0450:            }
0451:
0452:            /**
0453:             * Sets the upper bound for the thermometer.
0454:             *
0455:             * @param upper the upper bound.
0456:             * 
0457:             * @see #getUpperBound()
0458:             */
0459:            public void setUpperBound(double upper) {
0460:                this .upperBound = upper;
0461:                setAxisRange();
0462:            }
0463:
0464:            /**
0465:             * Sets the lower and upper bounds for the thermometer.
0466:             *
0467:             * @param lower  the lower bound.
0468:             * @param upper  the upper bound.
0469:             */
0470:            public void setRange(double lower, double upper) {
0471:                this .lowerBound = lower;
0472:                this .upperBound = upper;
0473:                setAxisRange();
0474:            }
0475:
0476:            /**
0477:             * Returns the padding for the thermometer.  This is the space inside the 
0478:             * plot area.
0479:             *
0480:             * @return The padding (never <code>null</code>).
0481:             * 
0482:             * @see #setPadding(RectangleInsets)
0483:             */
0484:            public RectangleInsets getPadding() {
0485:                return this .padding;
0486:            }
0487:
0488:            /**
0489:             * Sets the padding for the thermometer and sends a {@link PlotChangeEvent} 
0490:             * to all registered listeners.
0491:             *
0492:             * @param padding  the padding (<code>null</code> not permitted).
0493:             * 
0494:             * @see #getPadding()
0495:             */
0496:            public void setPadding(RectangleInsets padding) {
0497:                if (padding == null) {
0498:                    throw new IllegalArgumentException(
0499:                            "Null 'padding' argument.");
0500:                }
0501:                this .padding = padding;
0502:                notifyListeners(new PlotChangeEvent(this ));
0503:            }
0504:
0505:            /**
0506:             * Returns the stroke used to draw the thermometer outline.
0507:             *
0508:             * @return The stroke (never <code>null</code>).
0509:             * 
0510:             * @see #setThermometerStroke(Stroke)
0511:             * @see #getThermometerPaint()
0512:             */
0513:            public Stroke getThermometerStroke() {
0514:                return this .thermometerStroke;
0515:            }
0516:
0517:            /**
0518:             * Sets the stroke used to draw the thermometer outline and sends a 
0519:             * {@link PlotChangeEvent} to all registered listeners.
0520:             *
0521:             * @param s  the new stroke (<code>null</code> ignored).
0522:             * 
0523:             * @see #getThermometerStroke()
0524:             */
0525:            public void setThermometerStroke(Stroke s) {
0526:                if (s != null) {
0527:                    this .thermometerStroke = s;
0528:                    notifyListeners(new PlotChangeEvent(this ));
0529:                }
0530:            }
0531:
0532:            /**
0533:             * Returns the paint used to draw the thermometer outline.
0534:             *
0535:             * @return The paint (never <code>null</code>).
0536:             * 
0537:             * @see #setThermometerPaint(Paint)
0538:             * @see #getThermometerStroke()
0539:             */
0540:            public Paint getThermometerPaint() {
0541:                return this .thermometerPaint;
0542:            }
0543:
0544:            /**
0545:             * Sets the paint used to draw the thermometer outline and sends a 
0546:             * {@link PlotChangeEvent} to all registered listeners.
0547:             *
0548:             * @param paint  the new paint (<code>null</code> ignored).
0549:             * 
0550:             * @see #getThermometerPaint()
0551:             */
0552:            public void setThermometerPaint(Paint paint) {
0553:                if (paint != null) {
0554:                    this .thermometerPaint = paint;
0555:                    notifyListeners(new PlotChangeEvent(this ));
0556:                }
0557:            }
0558:
0559:            /**
0560:             * Returns a code indicating the unit display type.  This is one of
0561:             * {@link #UNITS_NONE}, {@link #UNITS_FAHRENHEIT}, {@link #UNITS_CELCIUS} 
0562:             * and {@link #UNITS_KELVIN}.
0563:             *
0564:             * @return The units type.
0565:             * 
0566:             * @see #setUnits(int)
0567:             */
0568:            public int getUnits() {
0569:                return this .units;
0570:            }
0571:
0572:            /**
0573:             * Sets the units to be displayed in the thermometer. Use one of the 
0574:             * following constants:
0575:             *
0576:             * <ul>
0577:             * <li>UNITS_NONE : no units displayed.</li>
0578:             * <li>UNITS_FAHRENHEIT : units displayed in Fahrenheit.</li>
0579:             * <li>UNITS_CELCIUS : units displayed in Celcius.</li>
0580:             * <li>UNITS_KELVIN : units displayed in Kelvin.</li>
0581:             * </ul>
0582:             *
0583:             * @param u  the new unit type.
0584:             * 
0585:             * @see #getUnits()
0586:             */
0587:            public void setUnits(int u) {
0588:                if ((u >= 0) && (u < UNITS.length)) {
0589:                    if (this .units != u) {
0590:                        this .units = u;
0591:                        notifyListeners(new PlotChangeEvent(this ));
0592:                    }
0593:                }
0594:            }
0595:
0596:            /**
0597:             * Sets the unit type.
0598:             *
0599:             * @param u  the unit type (<code>null</code> ignored).
0600:             * 
0601:             * @deprecated Use setUnits(int) instead.  Deprecated as of version 1.0.6,
0602:             *     because this method is a little obscure and redundant anyway.
0603:             */
0604:            public void setUnits(String u) {
0605:                if (u == null) {
0606:                    return;
0607:                }
0608:
0609:                u = u.toUpperCase().trim();
0610:                for (int i = 0; i < UNITS.length; ++i) {
0611:                    if (u.equals(UNITS[i].toUpperCase().trim())) {
0612:                        setUnits(i);
0613:                        i = UNITS.length;
0614:                    }
0615:                }
0616:            }
0617:
0618:            /**
0619:             * Returns a code indicating the location at which the value label is
0620:             * displayed.
0621:             *
0622:             * @return The location (one of {@link #NONE}, {@link #RIGHT}, 
0623:             *         {@link #LEFT} and {@link #BULB}.).
0624:             */
0625:            public int getValueLocation() {
0626:                return this .valueLocation;
0627:            }
0628:
0629:            /**
0630:             * Sets the location at which the current value is displayed and sends a
0631:             * {@link PlotChangeEvent} to all registered listeners.
0632:             * <P>
0633:             * The location can be one of the constants:
0634:             * <code>NONE</code>,
0635:             * <code>RIGHT</code>
0636:             * <code>LEFT</code> and
0637:             * <code>BULB</code>.
0638:             *
0639:             * @param location  the location.
0640:             */
0641:            public void setValueLocation(int location) {
0642:                if ((location >= 0) && (location < 4)) {
0643:                    this .valueLocation = location;
0644:                    notifyListeners(new PlotChangeEvent(this ));
0645:                } else {
0646:                    throw new IllegalArgumentException(
0647:                            "Location not recognised.");
0648:                }
0649:            }
0650:
0651:            /**
0652:             * Returns the axis location.
0653:             *
0654:             * @return The location (one of {@link #NONE}, {@link #LEFT} and 
0655:             *         {@link #RIGHT}).
0656:             *         
0657:             * @see #setAxisLocation(int)
0658:             */
0659:            public int getAxisLocation() {
0660:                return this .axisLocation;
0661:            }
0662:
0663:            /**
0664:             * Sets the location at which the axis is displayed relative to the 
0665:             * thermometer, and sends a {@link PlotChangeEvent} to all registered
0666:             * listeners.
0667:             *
0668:             * @param location  the location (one of {@link #NONE}, {@link #LEFT} and 
0669:             *         {@link #RIGHT}).
0670:             * 
0671:             * @see #getAxisLocation()
0672:             */
0673:            public void setAxisLocation(int location) {
0674:                if ((location >= 0) && (location < 3)) {
0675:                    this .axisLocation = location;
0676:                    notifyListeners(new PlotChangeEvent(this ));
0677:                } else {
0678:                    throw new IllegalArgumentException(
0679:                            "Location not recognised.");
0680:                }
0681:            }
0682:
0683:            /**
0684:             * Gets the font used to display the current value.
0685:             *
0686:             * @return The font.
0687:             * 
0688:             * @see #setValueFont(Font)
0689:             */
0690:            public Font getValueFont() {
0691:                return this .valueFont;
0692:            }
0693:
0694:            /**
0695:             * Sets the font used to display the current value.
0696:             *
0697:             * @param f  the new font (<code>null</code> not permitted).
0698:             * 
0699:             * @see #getValueFont()
0700:             */
0701:            public void setValueFont(Font f) {
0702:                if (f == null) {
0703:                    throw new IllegalArgumentException("Null 'font' argument.");
0704:                }
0705:                if (!this .valueFont.equals(f)) {
0706:                    this .valueFont = f;
0707:                    notifyListeners(new PlotChangeEvent(this ));
0708:                }
0709:            }
0710:
0711:            /**
0712:             * Gets the paint used to display the current value.
0713:             *
0714:             * @return The paint.
0715:             * 
0716:             * @see #setValuePaint(Paint)
0717:             */
0718:            public Paint getValuePaint() {
0719:                return this .valuePaint;
0720:            }
0721:
0722:            /**
0723:             * Sets the paint used to display the current value and sends a 
0724:             * {@link PlotChangeEvent} to all registered listeners.
0725:             *
0726:             * @param paint  the new paint (<code>null</code> not permitted).
0727:             * 
0728:             * @see #getValuePaint()
0729:             */
0730:            public void setValuePaint(Paint paint) {
0731:                if (paint == null) {
0732:                    throw new IllegalArgumentException("Null 'paint' argument.");
0733:                }
0734:                if (!this .valuePaint.equals(paint)) {
0735:                    this .valuePaint = paint;
0736:                    notifyListeners(new PlotChangeEvent(this ));
0737:                }
0738:            }
0739:
0740:            // FIXME: No getValueFormat() method?
0741:
0742:            /**
0743:             * Sets the formatter for the value label and sends a 
0744:             * {@link PlotChangeEvent} to all registered listeners.
0745:             *
0746:             * @param formatter  the new formatter (<code>null</code> not permitted).
0747:             */
0748:            public void setValueFormat(NumberFormat formatter) {
0749:                if (formatter == null) {
0750:                    throw new IllegalArgumentException(
0751:                            "Null 'formatter' argument.");
0752:                }
0753:                this .valueFormat = formatter;
0754:                notifyListeners(new PlotChangeEvent(this ));
0755:            }
0756:
0757:            /**
0758:             * Returns the default mercury paint.
0759:             *
0760:             * @return The paint (never <code>null</code>).
0761:             * 
0762:             * @see #setMercuryPaint(Paint)
0763:             */
0764:            public Paint getMercuryPaint() {
0765:                return this .mercuryPaint;
0766:            }
0767:
0768:            /**
0769:             * Sets the default mercury paint and sends a {@link PlotChangeEvent} to 
0770:             * all registered listeners.
0771:             *
0772:             * @param paint  the new paint (<code>null</code> not permitted).
0773:             * 
0774:             * @see #getMercuryPaint()
0775:             */
0776:            public void setMercuryPaint(Paint paint) {
0777:                if (paint == null) {
0778:                    throw new IllegalArgumentException("Null 'paint' argument.");
0779:                }
0780:                this .mercuryPaint = paint;
0781:                notifyListeners(new PlotChangeEvent(this ));
0782:            }
0783:
0784:            /**
0785:             * Returns the flag that controls whether not value lines are displayed.
0786:             *
0787:             * @return The flag.
0788:             * 
0789:             * @see #setShowValueLines(boolean)
0790:             * 
0791:             * @deprecated This flag doesn't do anything useful/visible.  Deprecated 
0792:             *     as of version 1.0.6.
0793:             */
0794:            public boolean getShowValueLines() {
0795:                return this .showValueLines;
0796:            }
0797:
0798:            /**
0799:             * Sets the display as to whether to show value lines in the output.
0800:             *
0801:             * @param b Whether to show value lines in the thermometer
0802:             * 
0803:             * @see #getShowValueLines()
0804:             * 
0805:             * @deprecated This flag doesn't do anything useful/visible.  Deprecated 
0806:             *     as of version 1.0.6.
0807:             */
0808:            public void setShowValueLines(boolean b) {
0809:                this .showValueLines = b;
0810:                notifyListeners(new PlotChangeEvent(this ));
0811:            }
0812:
0813:            /**
0814:             * Sets information for a particular range.
0815:             *
0816:             * @param range  the range to specify information about.
0817:             * @param low  the low value for the range
0818:             * @param hi  the high value for the range
0819:             */
0820:            public void setSubrangeInfo(int range, double low, double hi) {
0821:                setSubrangeInfo(range, low, hi, low, hi);
0822:            }
0823:
0824:            /**
0825:             * Sets the subrangeInfo attribute of the ThermometerPlot object
0826:             *
0827:             * @param range  the new rangeInfo value.
0828:             * @param rangeLow  the new rangeInfo value
0829:             * @param rangeHigh  the new rangeInfo value
0830:             * @param displayLow  the new rangeInfo value
0831:             * @param displayHigh  the new rangeInfo value
0832:             */
0833:            public void setSubrangeInfo(int range, double rangeLow,
0834:                    double rangeHigh, double displayLow, double displayHigh) {
0835:
0836:                if ((range >= 0) && (range < 3)) {
0837:                    setSubrange(range, rangeLow, rangeHigh);
0838:                    setDisplayRange(range, displayLow, displayHigh);
0839:                    setAxisRange();
0840:                    notifyListeners(new PlotChangeEvent(this ));
0841:                }
0842:
0843:            }
0844:
0845:            /**
0846:             * Sets the bounds for a subrange.
0847:             *
0848:             * @param range  the range type.
0849:             * @param low  the low value.
0850:             * @param high  the high value.
0851:             */
0852:            public void setSubrange(int range, double low, double high) {
0853:                if ((range >= 0) && (range < 3)) {
0854:                    this .subrangeInfo[range][RANGE_HIGH] = high;
0855:                    this .subrangeInfo[range][RANGE_LOW] = low;
0856:                }
0857:            }
0858:
0859:            /**
0860:             * Sets the displayed bounds for a sub range.
0861:             *
0862:             * @param range  the range type.
0863:             * @param low  the low value.
0864:             * @param high  the high value.
0865:             */
0866:            public void setDisplayRange(int range, double low, double high) {
0867:
0868:                if ((range >= 0) && (range < this .subrangeInfo.length)
0869:                        && isValidNumber(high) && isValidNumber(low)) {
0870:
0871:                    if (high > low) {
0872:                        this .subrangeInfo[range][DISPLAY_HIGH] = high;
0873:                        this .subrangeInfo[range][DISPLAY_LOW] = low;
0874:                    } else {
0875:                        this .subrangeInfo[range][DISPLAY_HIGH] = low;
0876:                        this .subrangeInfo[range][DISPLAY_LOW] = high;
0877:                    }
0878:
0879:                }
0880:
0881:            }
0882:
0883:            /**
0884:             * Gets the paint used for a particular subrange.
0885:             *
0886:             * @param range  the range (.
0887:             *
0888:             * @return The paint.
0889:             * 
0890:             * @see #setSubrangePaint(int, Paint)
0891:             */
0892:            public Paint getSubrangePaint(int range) {
0893:                if ((range >= 0) && (range < this .subrangePaint.length)) {
0894:                    return this .subrangePaint[range];
0895:                } else {
0896:                    return this .mercuryPaint;
0897:                }
0898:            }
0899:
0900:            /**
0901:             * Sets the paint to be used for a subrange and sends a 
0902:             * {@link PlotChangeEvent} to all registered listeners.
0903:             *
0904:             * @param range  the range (0, 1 or 2).
0905:             * @param paint  the paint to be applied (<code>null</code> not permitted).
0906:             * 
0907:             * @see #getSubrangePaint(int)
0908:             */
0909:            public void setSubrangePaint(int range, Paint paint) {
0910:                if ((range >= 0) && (range < this .subrangePaint.length)
0911:                        && (paint != null)) {
0912:                    this .subrangePaint[range] = paint;
0913:                    notifyListeners(new PlotChangeEvent(this ));
0914:                }
0915:            }
0916:
0917:            /**
0918:             * Returns a flag that controls whether or not the thermometer axis zooms 
0919:             * to display the subrange within which the data value falls.
0920:             *
0921:             * @return The flag.
0922:             */
0923:            public boolean getFollowDataInSubranges() {
0924:                return this .followDataInSubranges;
0925:            }
0926:
0927:            /**
0928:             * Sets the flag that controls whether or not the thermometer axis zooms 
0929:             * to display the subrange within which the data value falls.
0930:             *
0931:             * @param flag  the flag.
0932:             */
0933:            public void setFollowDataInSubranges(boolean flag) {
0934:                this .followDataInSubranges = flag;
0935:                notifyListeners(new PlotChangeEvent(this ));
0936:            }
0937:
0938:            /**
0939:             * Returns a flag that controls whether or not the mercury color changes 
0940:             * for each subrange.
0941:             *
0942:             * @return The flag.
0943:             * 
0944:             * @see #setUseSubrangePaint(boolean)
0945:             */
0946:            public boolean getUseSubrangePaint() {
0947:                return this .useSubrangePaint;
0948:            }
0949:
0950:            /**
0951:             * Sets the range colour change option.
0952:             *
0953:             * @param flag the new range colour change option
0954:             * 
0955:             * @see #getUseSubrangePaint()
0956:             */
0957:            public void setUseSubrangePaint(boolean flag) {
0958:                this .useSubrangePaint = flag;
0959:                notifyListeners(new PlotChangeEvent(this ));
0960:            }
0961:
0962:            /**
0963:             * Draws the plot on a Java 2D graphics device (such as the screen or a 
0964:             * printer).
0965:             *
0966:             * @param g2  the graphics device.
0967:             * @param area  the area within which the plot should be drawn.
0968:             * @param anchor  the anchor point (<code>null</code> permitted).
0969:             * @param parentState  the state from the parent plot, if there is one.
0970:             * @param info  collects info about the drawing.
0971:             */
0972:            public void draw(Graphics2D g2, Rectangle2D area, Point2D anchor,
0973:                    PlotState parentState, PlotRenderingInfo info) {
0974:
0975:                RoundRectangle2D outerStem = new RoundRectangle2D.Double();
0976:                RoundRectangle2D innerStem = new RoundRectangle2D.Double();
0977:                RoundRectangle2D mercuryStem = new RoundRectangle2D.Double();
0978:                Ellipse2D outerBulb = new Ellipse2D.Double();
0979:                Ellipse2D innerBulb = new Ellipse2D.Double();
0980:                String temp = null;
0981:                FontMetrics metrics = null;
0982:                if (info != null) {
0983:                    info.setPlotArea(area);
0984:                }
0985:
0986:                // adjust for insets...
0987:                RectangleInsets insets = getInsets();
0988:                insets.trim(area);
0989:                drawBackground(g2, area);
0990:
0991:                // adjust for padding...
0992:                Rectangle2D interior = (Rectangle2D) area.clone();
0993:                this .padding.trim(interior);
0994:                int midX = (int) (interior.getX() + (interior.getWidth() / 2));
0995:                int midY = (int) (interior.getY() + (interior.getHeight() / 2));
0996:                int stemTop = (int) (interior.getMinY() + BULB_RADIUS);
0997:                int stemBottom = (int) (interior.getMaxY() - BULB_DIAMETER);
0998:                Rectangle2D dataArea = new Rectangle2D.Double(midX
0999:                        - COLUMN_RADIUS, stemTop, COLUMN_RADIUS, stemBottom
1000:                        - stemTop);
1001:
1002:                outerBulb.setFrame(midX - BULB_RADIUS, stemBottom,
1003:                        BULB_DIAMETER, BULB_DIAMETER);
1004:
1005:                outerStem.setRoundRect(midX - COLUMN_RADIUS,
1006:                        interior.getMinY(), COLUMN_DIAMETER, stemBottom
1007:                                + BULB_DIAMETER - stemTop, COLUMN_DIAMETER,
1008:                        COLUMN_DIAMETER);
1009:
1010:                Area outerThermometer = new Area(outerBulb);
1011:                Area tempArea = new Area(outerStem);
1012:                outerThermometer.add(tempArea);
1013:
1014:                innerBulb.setFrame(midX - BULB_RADIUS + GAP_RADIUS, stemBottom
1015:                        + GAP_RADIUS, BULB_DIAMETER - GAP_DIAMETER,
1016:                        BULB_DIAMETER - GAP_DIAMETER);
1017:
1018:                innerStem.setRoundRect(midX - COLUMN_RADIUS + GAP_RADIUS,
1019:                        interior.getMinY() + GAP_RADIUS, COLUMN_DIAMETER
1020:                                - GAP_DIAMETER, stemBottom + BULB_DIAMETER
1021:                                - GAP_DIAMETER - stemTop, COLUMN_DIAMETER
1022:                                - GAP_DIAMETER, COLUMN_DIAMETER - GAP_DIAMETER);
1023:
1024:                Area innerThermometer = new Area(innerBulb);
1025:                tempArea = new Area(innerStem);
1026:                innerThermometer.add(tempArea);
1027:
1028:                if ((this .dataset != null) && (this .dataset.getValue() != null)) {
1029:                    double current = this .dataset.getValue().doubleValue();
1030:                    double ds = this .rangeAxis.valueToJava2D(current, dataArea,
1031:                            RectangleEdge.LEFT);
1032:
1033:                    int i = COLUMN_DIAMETER - GAP_DIAMETER; // already calculated
1034:                    int j = COLUMN_RADIUS - GAP_RADIUS; // already calculated
1035:                    int l = (i / 2);
1036:                    int k = (int) Math.round(ds);
1037:                    if (k < (GAP_RADIUS + interior.getMinY())) {
1038:                        k = (int) (GAP_RADIUS + interior.getMinY());
1039:                        l = BULB_RADIUS;
1040:                    }
1041:
1042:                    Area mercury = new Area(innerBulb);
1043:
1044:                    if (k < (stemBottom + BULB_RADIUS)) {
1045:                        mercuryStem.setRoundRect(midX - j, k, i,
1046:                                (stemBottom + BULB_RADIUS) - k, l, l);
1047:                        tempArea = new Area(mercuryStem);
1048:                        mercury.add(tempArea);
1049:                    }
1050:
1051:                    g2.setPaint(getCurrentPaint());
1052:                    g2.fill(mercury);
1053:
1054:                    // draw range indicators...
1055:                    if (this .subrangeIndicatorsVisible) {
1056:                        g2.setStroke(this .subrangeIndicatorStroke);
1057:                        Range range = this .rangeAxis.getRange();
1058:
1059:                        // draw start of normal range
1060:                        double value = this .subrangeInfo[NORMAL][RANGE_LOW];
1061:                        if (range.contains(value)) {
1062:                            double x = midX + COLUMN_RADIUS + 2;
1063:                            double y = this .rangeAxis.valueToJava2D(value,
1064:                                    dataArea, RectangleEdge.LEFT);
1065:                            Line2D line = new Line2D.Double(x, y, x + 10, y);
1066:                            g2.setPaint(this .subrangePaint[NORMAL]);
1067:                            g2.draw(line);
1068:                        }
1069:
1070:                        // draw start of warning range
1071:                        value = this .subrangeInfo[WARNING][RANGE_LOW];
1072:                        if (range.contains(value)) {
1073:                            double x = midX + COLUMN_RADIUS + 2;
1074:                            double y = this .rangeAxis.valueToJava2D(value,
1075:                                    dataArea, RectangleEdge.LEFT);
1076:                            Line2D line = new Line2D.Double(x, y, x + 10, y);
1077:                            g2.setPaint(this .subrangePaint[WARNING]);
1078:                            g2.draw(line);
1079:                        }
1080:
1081:                        // draw start of critical range
1082:                        value = this .subrangeInfo[CRITICAL][RANGE_LOW];
1083:                        if (range.contains(value)) {
1084:                            double x = midX + COLUMN_RADIUS + 2;
1085:                            double y = this .rangeAxis.valueToJava2D(value,
1086:                                    dataArea, RectangleEdge.LEFT);
1087:                            Line2D line = new Line2D.Double(x, y, x + 10, y);
1088:                            g2.setPaint(this .subrangePaint[CRITICAL]);
1089:                            g2.draw(line);
1090:                        }
1091:                    }
1092:
1093:                    // draw the axis...
1094:                    if ((this .rangeAxis != null) && (this .axisLocation != NONE)) {
1095:                        int drawWidth = AXIS_GAP;
1096:                        if (this .showValueLines) {
1097:                            drawWidth += COLUMN_DIAMETER;
1098:                        }
1099:                        Rectangle2D drawArea;
1100:                        double cursor = 0;
1101:
1102:                        switch (this .axisLocation) {
1103:                        case RIGHT:
1104:                            cursor = midX + COLUMN_RADIUS;
1105:                            drawArea = new Rectangle2D.Double(cursor, stemTop,
1106:                                    drawWidth, (stemBottom - stemTop + 1));
1107:                            this .rangeAxis.draw(g2, cursor, area, drawArea,
1108:                                    RectangleEdge.RIGHT, null);
1109:                            break;
1110:
1111:                        case LEFT:
1112:                        default:
1113:                            //cursor = midX - COLUMN_RADIUS - AXIS_GAP;
1114:                            cursor = midX - COLUMN_RADIUS;
1115:                            drawArea = new Rectangle2D.Double(cursor, stemTop,
1116:                                    drawWidth, (stemBottom - stemTop + 1));
1117:                            this .rangeAxis.draw(g2, cursor, area, drawArea,
1118:                                    RectangleEdge.LEFT, null);
1119:                            break;
1120:                        }
1121:
1122:                    }
1123:
1124:                    // draw text value on screen
1125:                    g2.setFont(this .valueFont);
1126:                    g2.setPaint(this .valuePaint);
1127:                    metrics = g2.getFontMetrics();
1128:                    switch (this .valueLocation) {
1129:                    case RIGHT:
1130:                        g2.drawString(this .valueFormat.format(current), midX
1131:                                + COLUMN_RADIUS + GAP_RADIUS, midY);
1132:                        break;
1133:                    case LEFT:
1134:                        String valueString = this .valueFormat.format(current);
1135:                        int stringWidth = metrics.stringWidth(valueString);
1136:                        g2.drawString(valueString, midX - COLUMN_RADIUS
1137:                                - GAP_RADIUS - stringWidth, midY);
1138:                        break;
1139:                    case BULB:
1140:                        temp = this .valueFormat.format(current);
1141:                        i = metrics.stringWidth(temp) / 2;
1142:                        g2.drawString(temp, midX - i, stemBottom + BULB_RADIUS
1143:                                + GAP_RADIUS);
1144:                        break;
1145:                    default:
1146:                    }
1147:                    /***/
1148:                }
1149:
1150:                g2.setPaint(this .thermometerPaint);
1151:                g2.setFont(this .valueFont);
1152:
1153:                //  draw units indicator
1154:                metrics = g2.getFontMetrics();
1155:                int tickX1 = midX - COLUMN_RADIUS - GAP_DIAMETER
1156:                        - metrics.stringWidth(UNITS[this .units]);
1157:                if (tickX1 > area.getMinX()) {
1158:                    g2.drawString(UNITS[this .units], tickX1, (int) (area
1159:                            .getMinY() + 20));
1160:                }
1161:
1162:                // draw thermometer outline
1163:                g2.setStroke(this .thermometerStroke);
1164:                g2.draw(outerThermometer);
1165:                g2.draw(innerThermometer);
1166:
1167:                drawOutline(g2, area);
1168:            }
1169:
1170:            /**
1171:             * A zoom method that does nothing.  Plots are required to support the 
1172:             * zoom operation.  In the case of a thermometer chart, it doesn't make 
1173:             * sense to zoom in or out, so the method is empty.
1174:             *
1175:             * @param percent  the zoom percentage.
1176:             */
1177:            public void zoom(double percent) {
1178:                // intentionally blank
1179:            }
1180:
1181:            /**
1182:             * Returns a short string describing the type of plot.
1183:             *
1184:             * @return A short string describing the type of plot.
1185:             */
1186:            public String getPlotType() {
1187:                return localizationResources.getString("Thermometer_Plot");
1188:            }
1189:
1190:            /**
1191:             * Checks to see if a new value means the axis range needs adjusting.
1192:             *
1193:             * @param event  the dataset change event.
1194:             */
1195:            public void datasetChanged(DatasetChangeEvent event) {
1196:                if (this .dataset != null) {
1197:                    Number vn = this .dataset.getValue();
1198:                    if (vn != null) {
1199:                        double value = vn.doubleValue();
1200:                        if (inSubrange(NORMAL, value)) {
1201:                            this .subrange = NORMAL;
1202:                        } else if (inSubrange(WARNING, value)) {
1203:                            this .subrange = WARNING;
1204:                        } else if (inSubrange(CRITICAL, value)) {
1205:                            this .subrange = CRITICAL;
1206:                        } else {
1207:                            this .subrange = -1;
1208:                        }
1209:                        setAxisRange();
1210:                    }
1211:                }
1212:                super .datasetChanged(event);
1213:            }
1214:
1215:            /**
1216:             * Returns the minimum value in either the domain or the range, whichever
1217:             * is displayed against the vertical axis for the particular type of plot
1218:             * implementing this interface.
1219:             *
1220:             * @return The minimum value in either the domain or the range.
1221:             * 
1222:             * @deprecated This method is not used.  Officially deprecated in version 
1223:             *         1.0.6.
1224:             */
1225:            public Number getMinimumVerticalDataValue() {
1226:                return new Double(this .lowerBound);
1227:            }
1228:
1229:            /**
1230:             * Returns the maximum value in either the domain or the range, whichever
1231:             * is displayed against the vertical axis for the particular type of plot
1232:             * implementing this interface.
1233:             *
1234:             * @return The maximum value in either the domain or the range
1235:             * 
1236:             * @deprecated This method is not used.  Officially deprecated in version 
1237:             *         1.0.6.
1238:             */
1239:            public Number getMaximumVerticalDataValue() {
1240:                return new Double(this .upperBound);
1241:            }
1242:
1243:            /**
1244:             * Returns the data range.
1245:             *
1246:             * @param axis  the axis.
1247:             *
1248:             * @return The range of data displayed.
1249:             */
1250:            public Range getDataRange(ValueAxis axis) {
1251:                return new Range(this .lowerBound, this .upperBound);
1252:            }
1253:
1254:            /**
1255:             * Sets the axis range to the current values in the rangeInfo array.
1256:             */
1257:            protected void setAxisRange() {
1258:                if ((this .subrange >= 0) && (this .followDataInSubranges)) {
1259:                    this .rangeAxis.setRange(new Range(
1260:                            this .subrangeInfo[this .subrange][DISPLAY_LOW],
1261:                            this .subrangeInfo[this .subrange][DISPLAY_HIGH]));
1262:                } else {
1263:                    this .rangeAxis.setRange(this .lowerBound, this .upperBound);
1264:                }
1265:            }
1266:
1267:            /**
1268:             * Returns the legend items for the plot.
1269:             *
1270:             * @return <code>null</code>.
1271:             */
1272:            public LegendItemCollection getLegendItems() {
1273:                return null;
1274:            }
1275:
1276:            /**
1277:             * Returns the orientation of the plot.
1278:             * 
1279:             * @return The orientation (always {@link PlotOrientation#VERTICAL}).
1280:             */
1281:            public PlotOrientation getOrientation() {
1282:                return PlotOrientation.VERTICAL;
1283:            }
1284:
1285:            /**
1286:             * Determine whether a number is valid and finite.
1287:             *
1288:             * @param d  the number to be tested.
1289:             *
1290:             * @return <code>true</code> if the number is valid and finite, and 
1291:             *         <code>false</code> otherwise.
1292:             */
1293:            protected static boolean isValidNumber(double d) {
1294:                return (!(Double.isNaN(d) || Double.isInfinite(d)));
1295:            }
1296:
1297:            /**
1298:             * Returns true if the value is in the specified range, and false otherwise.
1299:             *
1300:             * @param subrange  the subrange.
1301:             * @param value  the value to check.
1302:             *
1303:             * @return A boolean.
1304:             */
1305:            private boolean inSubrange(int subrange, double value) {
1306:                return (value > this .subrangeInfo[subrange][RANGE_LOW] && value <= this .subrangeInfo[subrange][RANGE_HIGH]);
1307:            }
1308:
1309:            /**
1310:             * Returns the mercury paint corresponding to the current data value.
1311:             * Called from the {@link #draw(Graphics2D, Rectangle2D, Point2D, 
1312:             * PlotState, PlotRenderingInfo)} method.
1313:             *
1314:             * @return The paint (never <code>null</code>).
1315:             */
1316:            private Paint getCurrentPaint() {
1317:                Paint result = this .mercuryPaint;
1318:                if (this .useSubrangePaint) {
1319:                    double value = this .dataset.getValue().doubleValue();
1320:                    if (inSubrange(NORMAL, value)) {
1321:                        result = this .subrangePaint[NORMAL];
1322:                    } else if (inSubrange(WARNING, value)) {
1323:                        result = this .subrangePaint[WARNING];
1324:                    } else if (inSubrange(CRITICAL, value)) {
1325:                        result = this .subrangePaint[CRITICAL];
1326:                    }
1327:                }
1328:                return result;
1329:            }
1330:
1331:            /**
1332:             * Tests this plot for equality with another object.  The plot's dataset
1333:             * is not considered in the test.
1334:             *
1335:             * @param obj  the object (<code>null</code> permitted).
1336:             *
1337:             * @return <code>true</code> or <code>false</code>.
1338:             */
1339:            public boolean equals(Object obj) {
1340:                if (obj == this ) {
1341:                    return true;
1342:                }
1343:                if (!(obj instanceof  ThermometerPlot)) {
1344:                    return false;
1345:                }
1346:                ThermometerPlot that = (ThermometerPlot) obj;
1347:                if (!super .equals(obj)) {
1348:                    return false;
1349:                }
1350:                if (!ObjectUtilities.equal(this .rangeAxis, that.rangeAxis)) {
1351:                    return false;
1352:                }
1353:                if (this .axisLocation != that.axisLocation) {
1354:                    return false;
1355:                }
1356:                if (this .lowerBound != that.lowerBound) {
1357:                    return false;
1358:                }
1359:                if (this .upperBound != that.upperBound) {
1360:                    return false;
1361:                }
1362:                if (!ObjectUtilities.equal(this .padding, that.padding)) {
1363:                    return false;
1364:                }
1365:                if (!ObjectUtilities.equal(this .thermometerStroke,
1366:                        that.thermometerStroke)) {
1367:                    return false;
1368:                }
1369:                if (!PaintUtilities.equal(this .thermometerPaint,
1370:                        that.thermometerPaint)) {
1371:                    return false;
1372:                }
1373:                if (this .units != that.units) {
1374:                    return false;
1375:                }
1376:                if (this .valueLocation != that.valueLocation) {
1377:                    return false;
1378:                }
1379:                if (!ObjectUtilities.equal(this .valueFont, that.valueFont)) {
1380:                    return false;
1381:                }
1382:                if (!PaintUtilities.equal(this .valuePaint, that.valuePaint)) {
1383:                    return false;
1384:                }
1385:                if (!ObjectUtilities.equal(this .valueFormat, that.valueFormat)) {
1386:                    return false;
1387:                }
1388:                if (!PaintUtilities.equal(this .mercuryPaint, that.mercuryPaint)) {
1389:                    return false;
1390:                }
1391:                if (this .showValueLines != that.showValueLines) {
1392:                    return false;
1393:                }
1394:                if (this .subrange != that.subrange) {
1395:                    return false;
1396:                }
1397:                if (this .followDataInSubranges != that.followDataInSubranges) {
1398:                    return false;
1399:                }
1400:                if (!equal(this .subrangeInfo, that.subrangeInfo)) {
1401:                    return false;
1402:                }
1403:                if (this .useSubrangePaint != that.useSubrangePaint) {
1404:                    return false;
1405:                }
1406:                for (int i = 0; i < this .subrangePaint.length; i++) {
1407:                    if (!PaintUtilities.equal(this .subrangePaint[i],
1408:                            that.subrangePaint[i])) {
1409:                        return false;
1410:                    }
1411:                }
1412:                return true;
1413:            }
1414:
1415:            /**
1416:             * Tests two double[][] arrays for equality.
1417:             * 
1418:             * @param array1  the first array (<code>null</code> permitted).
1419:             * @param array2  the second arrray (<code>null</code> permitted).
1420:             * 
1421:             * @return A boolean.
1422:             */
1423:            private static boolean equal(double[][] array1, double[][] array2) {
1424:                if (array1 == null) {
1425:                    return (array2 == null);
1426:                }
1427:                if (array2 == null) {
1428:                    return false;
1429:                }
1430:                if (array1.length != array2.length) {
1431:                    return false;
1432:                }
1433:                for (int i = 0; i < array1.length; i++) {
1434:                    if (!Arrays.equals(array1[i], array2[i])) {
1435:                        return false;
1436:                    }
1437:                }
1438:                return true;
1439:            }
1440:
1441:            /**
1442:             * Returns a clone of the plot.
1443:             *
1444:             * @return A clone.
1445:             *
1446:             * @throws CloneNotSupportedException  if the plot cannot be cloned.
1447:             */
1448:            public Object clone() throws CloneNotSupportedException {
1449:
1450:                ThermometerPlot clone = (ThermometerPlot) super .clone();
1451:
1452:                if (clone.dataset != null) {
1453:                    clone.dataset.addChangeListener(clone);
1454:                }
1455:                clone.rangeAxis = (ValueAxis) ObjectUtilities
1456:                        .clone(this .rangeAxis);
1457:                if (clone.rangeAxis != null) {
1458:                    clone.rangeAxis.setPlot(clone);
1459:                    clone.rangeAxis.addChangeListener(clone);
1460:                }
1461:                clone.valueFormat = (NumberFormat) this .valueFormat.clone();
1462:                clone.subrangePaint = (Paint[]) this .subrangePaint.clone();
1463:
1464:                return clone;
1465:
1466:            }
1467:
1468:            /**
1469:             * Provides serialization support.
1470:             *
1471:             * @param stream  the output stream.
1472:             *
1473:             * @throws IOException  if there is an I/O error.
1474:             */
1475:            private void writeObject(ObjectOutputStream stream)
1476:                    throws IOException {
1477:                stream.defaultWriteObject();
1478:                SerialUtilities.writeStroke(this .thermometerStroke, stream);
1479:                SerialUtilities.writePaint(this .thermometerPaint, stream);
1480:                SerialUtilities.writePaint(this .valuePaint, stream);
1481:                SerialUtilities.writePaint(this .mercuryPaint, stream);
1482:                SerialUtilities.writeStroke(this .subrangeIndicatorStroke,
1483:                        stream);
1484:                SerialUtilities.writeStroke(this .rangeIndicatorStroke, stream);
1485:                for (int i = 0; i < 3; i++) {
1486:                    SerialUtilities.writePaint(this .subrangePaint[i], stream);
1487:                }
1488:            }
1489:
1490:            /**
1491:             * Provides serialization support.
1492:             *
1493:             * @param stream  the input stream.
1494:             *
1495:             * @throws IOException  if there is an I/O error.
1496:             * @throws ClassNotFoundException  if there is a classpath problem.
1497:             */
1498:            private void readObject(ObjectInputStream stream)
1499:                    throws IOException, ClassNotFoundException {
1500:                stream.defaultReadObject();
1501:                this .thermometerStroke = SerialUtilities.readStroke(stream);
1502:                this .thermometerPaint = SerialUtilities.readPaint(stream);
1503:                this .valuePaint = SerialUtilities.readPaint(stream);
1504:                this .mercuryPaint = SerialUtilities.readPaint(stream);
1505:                this .subrangeIndicatorStroke = SerialUtilities
1506:                        .readStroke(stream);
1507:                this .rangeIndicatorStroke = SerialUtilities.readStroke(stream);
1508:                this .subrangePaint = new Paint[3];
1509:                for (int i = 0; i < 3; i++) {
1510:                    this .subrangePaint[i] = SerialUtilities.readPaint(stream);
1511:                }
1512:                if (this .rangeAxis != null) {
1513:                    this .rangeAxis.addChangeListener(this );
1514:                }
1515:            }
1516:
1517:            /**
1518:             * Multiplies the range on the domain axis/axes by the specified factor.
1519:             *
1520:             * @param factor  the zoom factor.
1521:             * @param state  the plot state.
1522:             * @param source  the source point.
1523:             */
1524:            public void zoomDomainAxes(double factor, PlotRenderingInfo state,
1525:                    Point2D source) {
1526:                // no domain axis to zoom
1527:            }
1528:
1529:            /**
1530:             * Multiplies the range on the range axis/axes by the specified factor.
1531:             *
1532:             * @param factor  the zoom factor.
1533:             * @param state  the plot state.
1534:             * @param source  the source point.
1535:             */
1536:            public void zoomRangeAxes(double factor, PlotRenderingInfo state,
1537:                    Point2D source) {
1538:                this .rangeAxis.resizeRange(factor);
1539:            }
1540:
1541:            /**
1542:             * This method does nothing.
1543:             *
1544:             * @param lowerPercent  the lower percent.
1545:             * @param upperPercent  the upper percent.
1546:             * @param state  the plot state.
1547:             * @param source  the source point.
1548:             */
1549:            public void zoomDomainAxes(double lowerPercent,
1550:                    double upperPercent, PlotRenderingInfo state, Point2D source) {
1551:                // no domain axis to zoom
1552:            }
1553:
1554:            /**
1555:             * Zooms the range axes.
1556:             *
1557:             * @param lowerPercent  the lower percent.
1558:             * @param upperPercent  the upper percent.
1559:             * @param state  the plot state.
1560:             * @param source  the source point.
1561:             */
1562:            public void zoomRangeAxes(double lowerPercent, double upperPercent,
1563:                    PlotRenderingInfo state, Point2D source) {
1564:                this .rangeAxis.zoomRange(lowerPercent, upperPercent);
1565:            }
1566:
1567:            /**
1568:             * Returns <code>false</code>.
1569:             * 
1570:             * @return A boolean.
1571:             */
1572:            public boolean isDomainZoomable() {
1573:                return false;
1574:            }
1575:
1576:            /**
1577:             * Returns <code>true</code>.
1578:             * 
1579:             * @return A boolean.
1580:             */
1581:            public boolean isRangeZoomable() {
1582:                return true;
1583:            }
1584:
1585:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.