1:
77:
78: package ;
79:
80: import ;
81: import ;
82: import ;
83: import ;
84: import ;
85: import ;
86: import ;
87: import ;
88: import ;
89: import ;
90: import ;
91: import ;
92: import ;
93: import ;
94: import ;
95: import ;
96: import ;
97: import ;
98: import ;
99: import ;
100: import ;
101:
102: import ;
103: import ;
104: import ;
105: import ;
106: import ;
107: import ;
108: import ;
109: import ;
110: import ;
111: import ;
112: import ;
113: import ;
114: import ;
115: import ;
116:
117:
137: public class ThermometerPlot extends Plot implements ValueAxisPlot,
138: Zoomable,
139: Cloneable,
140: Serializable {
141:
142:
143: private static final long serialVersionUID = 4087093313147984390L;
144:
145:
146: public static final int UNITS_NONE = 0;
147:
148:
149: public static final int UNITS_FAHRENHEIT = 1;
150:
151:
152: public static final int UNITS_CELCIUS = 2;
153:
154:
155: public static final int UNITS_KELVIN = 3;
156:
157:
158: public static final int NONE = 0;
159:
160:
161: public static final int RIGHT = 1;
162:
163:
164: public static final int LEFT = 2;
165:
166:
167: public static final int BULB = 3;
168:
169:
170: public static final int NORMAL = 0;
171:
172:
173: public static final int WARNING = 1;
174:
175:
176: public static final int CRITICAL = 2;
177:
178:
179: protected static final int BULB_RADIUS = 40;
180:
181:
182: protected static final int BULB_DIAMETER = BULB_RADIUS * 2;
183:
184:
185: protected static final int COLUMN_RADIUS = 20;
186:
187:
188: protected static final int COLUMN_DIAMETER = COLUMN_RADIUS * 2;
189:
190:
191: protected static final int GAP_RADIUS = 5;
192:
193:
194: protected static final int GAP_DIAMETER = GAP_RADIUS * 2;
195:
196:
197: protected static final int AXIS_GAP = 10;
198:
199:
200: protected static final String[] UNITS
201: = {"", "\u00B0F", "\u00B0C", "\u00B0K"};
202:
203:
204: protected static final int RANGE_LOW = 0;
205:
206:
207: protected static final int RANGE_HIGH = 1;
208:
209:
210: protected static final int DISPLAY_LOW = 2;
211:
212:
213: protected static final int DISPLAY_HIGH = 3;
214:
215:
216: protected static final double DEFAULT_LOWER_BOUND = 0.0;
217:
218:
219: protected static final double DEFAULT_UPPER_BOUND = 100.0;
220:
221:
222: private ValueDataset dataset;
223:
224:
225: private ValueAxis rangeAxis;
226:
227:
228: private double lowerBound = DEFAULT_LOWER_BOUND;
229:
230:
231: private double upperBound = DEFAULT_UPPER_BOUND;
232:
233:
236: private RectangleInsets padding;
237:
238:
239: private transient Stroke thermometerStroke = new BasicStroke(1.0f);
240:
241:
242: private transient Paint thermometerPaint = Color.black;
243:
244:
245: private int units = UNITS_CELCIUS;
246:
247:
248: private int valueLocation = BULB;
249:
250:
251: private int axisLocation = LEFT;
252:
253:
254: private Font valueFont = new Font("SansSerif", Font.BOLD, 16);
255:
256:
257: private transient Paint valuePaint = Color.white;
258:
259:
260: private NumberFormat valueFormat = new DecimalFormat();
261:
262:
263: private transient Paint mercuryPaint = Color.lightGray;
264:
265:
266: private boolean showValueLines = false;
267:
268:
269: private int subrange = -1;
270:
271:
272: private double[][] subrangeInfo = {
273: {0.0, 50.0, 0.0, 50.0},
274: {50.0, 75.0, 50.0, 75.0},
275: {75.0, 100.0, 75.0, 100.0}
276: };
277:
278:
282: private boolean followDataInSubranges = false;
283:
284:
288: private boolean useSubrangePaint = true;
289:
290:
291: private Paint[] subrangePaint = {
292: Color.green,
293: Color.orange,
294: Color.red
295: };
296:
297:
298: private boolean subrangeIndicatorsVisible = true;
299:
300:
301: private transient Stroke subrangeIndicatorStroke = new BasicStroke(2.0f);
302:
303:
304: private transient Stroke rangeIndicatorStroke = new BasicStroke(3.0f);
305:
306:
307: protected static ResourceBundle localizationResources =
308: ResourceBundle.getBundle("org.jfree.chart.plot.LocalizationBundle");
309:
310:
313: public ThermometerPlot() {
314: this(new DefaultValueDataset());
315: }
316:
317:
322: public ThermometerPlot(ValueDataset dataset) {
323:
324: super();
325:
326: this.padding = new RectangleInsets(
327: UnitType.RELATIVE, 0.05, 0.05, 0.05, 0.05
328: );
329: this.dataset = dataset;
330: if (dataset != null) {
331: dataset.addChangeListener(this);
332: }
333: NumberAxis axis = new NumberAxis(null);
334: axis.setStandardTickUnits(NumberAxis.createIntegerTickUnits());
335: axis.setAxisLineVisible(false);
336:
337: setRangeAxis(axis);
338: setAxisRange();
339: }
340:
341:
346: public ValueDataset getDataset() {
347: return this.dataset;
348: }
349:
350:
356: public void setDataset(ValueDataset dataset) {
357:
358:
359:
360: ValueDataset existing = this.dataset;
361: if (existing != null) {
362: existing.removeChangeListener(this);
363: }
364:
365:
366: this.dataset = dataset;
367: if (dataset != null) {
368: setDatasetGroup(dataset.getGroup());
369: dataset.addChangeListener(this);
370: }
371:
372:
373: DatasetChangeEvent event = new DatasetChangeEvent(this, dataset);
374: datasetChanged(event);
375:
376: }
377:
378:
383: public ValueAxis getRangeAxis() {
384: return this.rangeAxis;
385: }
386:
387:
392: public void setRangeAxis(ValueAxis axis) {
393:
394: if (axis != null) {
395: axis.setPlot(this);
396: axis.addChangeListener(this);
397: }
398:
399:
400: if (this.rangeAxis != null) {
401: this.rangeAxis.removeChangeListener(this);
402: }
403:
404: this.rangeAxis = axis;
405:
406: }
407:
408:
415: public double getLowerBound() {
416: return this.lowerBound;
417: }
418:
419:
424: public void setLowerBound(double lower) {
425: this.lowerBound = lower;
426: setAxisRange();
427: }
428:
429:
435: public double getUpperBound() {
436: return this.upperBound;
437: }
438:
439:
444: public void setUpperBound(double upper) {
445: this.upperBound = upper;
446: setAxisRange();
447: }
448:
449:
455: public void setRange(double lower, double upper) {
456: this.lowerBound = lower;
457: this.upperBound = upper;
458: setAxisRange();
459: }
460:
461:
467: public RectangleInsets getPadding() {
468: return this.padding;
469: }
470:
471:
476: public void setPadding(RectangleInsets padding) {
477: this.padding = padding;
478: notifyListeners(new PlotChangeEvent(this));
479: }
480:
481:
486: public Stroke getThermometerStroke() {
487: return this.thermometerStroke;
488: }
489:
490:
495: public void setThermometerStroke(Stroke s) {
496: if (s != null) {
497: this.thermometerStroke = s;
498: notifyListeners(new PlotChangeEvent(this));
499: }
500: }
501:
502:
507: public Paint getThermometerPaint() {
508: return this.thermometerPaint;
509: }
510:
511:
516: public void setThermometerPaint(Paint paint) {
517: if (paint != null) {
518: this.thermometerPaint = paint;
519: notifyListeners(new PlotChangeEvent(this));
520: }
521: }
522:
523:
528: public int getUnits() {
529: return this.units;
530: }
531:
532:
546: public void setUnits(int u) {
547: if ((u >= 0) && (u < UNITS.length)) {
548: if (this.units != u) {
549: this.units = u;
550: notifyListeners(new PlotChangeEvent(this));
551: }
552: }
553: }
554:
555:
560: public void setUnits(String u) {
561: if (u == null) {
562: return;
563: }
564:
565: u = u.toUpperCase().trim();
566: for (int i = 0; i < UNITS.length; ++i) {
567: if (u.equals(UNITS[i].toUpperCase().trim())) {
568: setUnits(i);
569: i = UNITS.length;
570: }
571: }
572: }
573:
574:
579: public int getValueLocation() {
580: return this.valueLocation;
581: }
582:
583:
594: public void setValueLocation(int location) {
595: if ((location >= 0) && (location < 4)) {
596: this.valueLocation = location;
597: notifyListeners(new PlotChangeEvent(this));
598: }
599: else {
600: throw new IllegalArgumentException("Location not recognised.");
601: }
602: }
603:
604:
615: public void setAxisLocation(int location) {
616: if ((location >= 0) && (location < 3)) {
617: this.axisLocation = location;
618: notifyListeners(new PlotChangeEvent(this));
619: }
620: else {
621: throw new IllegalArgumentException("Location not recognised.");
622: }
623: }
624:
625:
630: public int getAxisLocation() {
631: return this.axisLocation;
632: }
633:
634:
639: public Font getValueFont() {
640: return this.valueFont;
641: }
642:
643:
648: public void setValueFont(Font f) {
649: if ((f != null) && (!this.valueFont.equals(f))) {
650: this.valueFont = f;
651: notifyListeners(new PlotChangeEvent(this));
652: }
653: }
654:
655:
660: public Paint getValuePaint() {
661: return this.valuePaint;
662: }
663:
664:
669: public void setValuePaint(Paint p) {
670: if ((p != null) && (!this.valuePaint.equals(p))) {
671: this.valuePaint = p;
672: notifyListeners(new PlotChangeEvent(this));
673: }
674: }
675:
676:
681: public void setValueFormat(NumberFormat formatter) {
682: if (formatter != null) {
683: this.valueFormat = formatter;
684: notifyListeners(new PlotChangeEvent(this));
685: }
686: }
687:
688:
693: public Paint getMercuryPaint() {
694: return this.mercuryPaint;
695: }
696:
697:
702: public void setMercuryPaint(Paint paint) {
703: this.mercuryPaint = paint;
704: notifyListeners(new PlotChangeEvent(this));
705: }
706:
707:
712: public boolean getShowValueLines() {
713: return this.showValueLines;
714: }
715:
716:
721: public void setShowValueLines(boolean b) {
722: this.showValueLines = b;
723: notifyListeners(new PlotChangeEvent(this));
724: }
725:
726:
733: public void setSubrangeInfo(int range, double low, double hi) {
734: setSubrangeInfo(range, low, hi, low, hi);
735: }
736:
737:
746: public void setSubrangeInfo(int range,
747: double rangeLow, double rangeHigh,
748: double displayLow, double displayHigh) {
749:
750: if ((range >= 0) && (range < 3)) {
751: setSubrange(range, rangeLow, rangeHigh);
752: setDisplayRange(range, displayLow, displayHigh);
753: setAxisRange();
754: notifyListeners(new PlotChangeEvent(this));
755: }
756:
757: }
758:
759:
766: public void setSubrange(int range, double low, double high) {
767: if ((range >= 0) && (range < 3)) {
768: this.subrangeInfo[range][RANGE_HIGH] = high;
769: this.subrangeInfo[range][RANGE_LOW] = low;
770: }
771: }
772:
773:
780: public void setDisplayRange(int range, double low, double high) {
781:
782: if ((range >= 0) && (range < this.subrangeInfo.length)
783: && isValidNumber(high) && isValidNumber(low)) {
784:
785: if (high > low) {
786: this.subrangeInfo[range][DISPLAY_HIGH] = high;
787: this.subrangeInfo[range][DISPLAY_LOW] = low;
788: }
789: else {
790: this.subrangeInfo[range][DISPLAY_HIGH] = low;
791: this.subrangeInfo[range][DISPLAY_LOW] = high;
792: }
793:
794: }
795:
796: }
797:
798:
805: public Paint getSubrangePaint(int range) {
806: if ((range >= 0) && (range < this.subrangePaint.length)) {
807: return this.subrangePaint[range];
808: }
809: else {
810: return this.mercuryPaint;
811: }
812: }
813:
814:
820: public void setSubrangePaint(int range, Paint paint) {
821: if ((range >= 0)
822: && (range < this.subrangePaint.length) && (paint != null)) {
823: this.subrangePaint[range] = paint;
824: notifyListeners(new PlotChangeEvent(this));
825: }
826: }
827:
828:
834: public boolean getFollowDataInSubranges() {
835: return this.followDataInSubranges;
836: }
837:
838:
844: public void setFollowDataInSubranges(boolean flag) {
845: this.followDataInSubranges = flag;
846: notifyListeners(new PlotChangeEvent(this));
847: }
848:
849:
855: public boolean getUseSubrangePaint() {
856: return this.useSubrangePaint;
857: }
858:
859:
864: public void setUseSubrangePaint(boolean flag) {
865: this.useSubrangePaint = flag;
866: notifyListeners(new PlotChangeEvent(this));
867: }
868:
869:
879: public void draw(Graphics2D g2, Rectangle2D area, Point2D anchor,
880: PlotState parentState,
881: PlotRenderingInfo info) {
882:
883: RoundRectangle2D outerStem = new RoundRectangle2D.Double();
884: RoundRectangle2D innerStem = new RoundRectangle2D.Double();
885: RoundRectangle2D mercuryStem = new RoundRectangle2D.Double();
886: Ellipse2D outerBulb = new Ellipse2D.Double();
887: Ellipse2D innerBulb = new Ellipse2D.Double();
888: String temp = null;
889: FontMetrics metrics = null;
890: if (info != null) {
891: info.setPlotArea(area);
892: }
893:
894:
895: RectangleInsets insets = getInsets();
896: insets.trim(area);
897: drawBackground(g2, area);
898:
899:
900:
901: int midX = (int) (area.getX() + (area.getWidth() / 2));
902: int midY = (int) (area.getY() + (area.getHeight() / 2));
903: int stemTop = (int) (area.getMinY() + BULB_RADIUS);
904: int stemBottom = (int) (area.getMaxY() - BULB_DIAMETER);
905: Rectangle2D dataArea = new Rectangle2D.Double(
906: midX - COLUMN_RADIUS, stemTop, COLUMN_RADIUS, stemBottom - stemTop
907: );
908:
909: outerBulb.setFrame(
910: midX - BULB_RADIUS, stemBottom, BULB_DIAMETER, BULB_DIAMETER
911: );
912:
913: outerStem.setRoundRect(
914: midX - COLUMN_RADIUS, area.getMinY(), COLUMN_DIAMETER,
915: stemBottom + BULB_DIAMETER - stemTop,
916: COLUMN_DIAMETER, COLUMN_DIAMETER
917: );
918:
919: Area outerThermometer = new Area(outerBulb);
920: Area tempArea = new Area(outerStem);
921: outerThermometer.add(tempArea);
922:
923: innerBulb.setFrame(
924: midX - BULB_RADIUS + GAP_RADIUS, stemBottom + GAP_RADIUS,
925: BULB_DIAMETER - GAP_DIAMETER, BULB_DIAMETER - GAP_DIAMETER
926: );
927:
928: innerStem.setRoundRect(
929: midX - COLUMN_RADIUS + GAP_RADIUS, area.getMinY() + GAP_RADIUS,
930: COLUMN_DIAMETER - GAP_DIAMETER,
931: stemBottom + BULB_DIAMETER - GAP_DIAMETER - stemTop,
932: COLUMN_DIAMETER - GAP_DIAMETER, COLUMN_DIAMETER - GAP_DIAMETER
933: );
934:
935: Area innerThermometer = new Area(innerBulb);
936: tempArea = new Area(innerStem);
937: innerThermometer.add(tempArea);
938:
939: if ((this.dataset != null) && (this.dataset.getValue() != null)) {
940: double current = this.dataset.getValue().doubleValue();
941: double ds = this.rangeAxis.valueToJava2D(
942: current, dataArea, RectangleEdge.LEFT
943: );
944:
945: int i = COLUMN_DIAMETER - GAP_DIAMETER;
946: int j = COLUMN_RADIUS - GAP_RADIUS;
947: int l = (i / 2);
948: int k = (int) Math.round(ds);
949: if (k < (GAP_RADIUS + area.getMinY())) {
950: k = (int) (GAP_RADIUS + area.getMinY());
951: l = BULB_RADIUS;
952: }
953:
954: Area mercury = new Area(innerBulb);
955:
956: if (k < (stemBottom + BULB_RADIUS)) {
957: mercuryStem.setRoundRect(
958: midX - j, k, i, (stemBottom + BULB_RADIUS) - k, l, l
959: );
960: tempArea = new Area(mercuryStem);
961: mercury.add(tempArea);
962: }
963:
964: g2.setPaint(getCurrentPaint());
965: g2.fill(mercury);
966:
967:
968: if (this.subrangeIndicatorsVisible) {
969: g2.setStroke(this.subrangeIndicatorStroke);
970: Range range = this.rangeAxis.getRange();
971:
972:
973: double value = this.subrangeInfo[NORMAL][RANGE_LOW];
974: if (range.contains(value)) {
975: double x = midX + COLUMN_RADIUS + 2;
976: double y = this.rangeAxis.valueToJava2D(
977: value, dataArea, RectangleEdge.LEFT
978: );
979: Line2D line = new Line2D.Double(x, y, x + 10, y);
980: g2.setPaint(this.subrangePaint[NORMAL]);
981: g2.draw(line);
982: }
983:
984:
985: value = this.subrangeInfo[WARNING][RANGE_LOW];
986: if (range.contains(value)) {
987: double x = midX + COLUMN_RADIUS + 2;
988: double y = this.rangeAxis.valueToJava2D(
989: value, dataArea, RectangleEdge.LEFT
990: );
991: Line2D line = new Line2D.Double(x, y, x + 10, y);
992: g2.setPaint(this.subrangePaint[WARNING]);
993: g2.draw(line);
994: }
995:
996:
997: value = this.subrangeInfo[CRITICAL][RANGE_LOW];
998: if (range.contains(value)) {
999: double x = midX + COLUMN_RADIUS + 2;
1000: double y = this.rangeAxis.valueToJava2D(
1001: value, dataArea, RectangleEdge.LEFT
1002: );
1003: Line2D line = new Line2D.Double(x, y, x + 10, y);
1004: g2.setPaint(this.subrangePaint[CRITICAL]);
1005: g2.draw(line);
1006: }
1007: }
1008:
1009:
1010: if ((this.rangeAxis != null) && (this.axisLocation != NONE)) {
1011: int drawWidth = AXIS_GAP;
1012: if (this.showValueLines) {
1013: drawWidth += COLUMN_DIAMETER;
1014: }
1015: Rectangle2D drawArea;
1016: double cursor = 0;
1017:
1018: switch (this.axisLocation) {
1019: case RIGHT:
1020: cursor = midX + COLUMN_RADIUS;
1021: drawArea = new Rectangle2D.Double(
1022: cursor,
1023: stemTop,
1024: drawWidth,
1025: (stemBottom - stemTop + 1)
1026: );
1027: this.rangeAxis.draw(
1028: g2, cursor, area, drawArea,
1029: RectangleEdge.RIGHT, null
1030: );
1031: break;
1032:
1033: case LEFT:
1034: default:
1035:
1036: cursor = midX - COLUMN_RADIUS;
1037: drawArea = new Rectangle2D.Double(
1038: cursor,
1039: stemTop,
1040: drawWidth,
1041: (stemBottom - stemTop + 1)
1042: );
1043: this.rangeAxis.draw(
1044: g2, cursor, area, drawArea,
1045: RectangleEdge.LEFT, null
1046: );
1047: break;
1048: }
1049:
1050: }
1051:
1052:
1053: g2.setFont(this.valueFont);
1054: g2.setPaint(this.valuePaint);
1055: metrics = g2.getFontMetrics();
1056: switch (this.valueLocation) {
1057: case RIGHT:
1058: g2.drawString(
1059: this.valueFormat.format(current),
1060: midX + COLUMN_RADIUS + GAP_RADIUS, midY
1061: );
1062: break;
1063: case LEFT:
1064: String valueString = this.valueFormat.format(current);
1065: int stringWidth = metrics.stringWidth(valueString);
1066: g2.drawString(
1067: valueString,
1068: midX - COLUMN_RADIUS - GAP_RADIUS - stringWidth, midY
1069: );
1070: break;
1071: case BULB:
1072: temp = this.valueFormat.format(current);
1073: i = metrics.stringWidth(temp) / 2;
1074: g2.drawString(
1075: temp, midX - i,
1076: stemBottom + BULB_RADIUS + GAP_RADIUS
1077: );
1078: break;
1079: default:
1080: }
1081:
1082: }
1083:
1084: g2.setPaint(this.thermometerPaint);
1085: g2.setFont(this.valueFont);
1086:
1087:
1088: metrics = g2.getFontMetrics();
1089: int tickX1 = midX - COLUMN_RADIUS - GAP_DIAMETER
1090: - metrics.stringWidth(UNITS[this.units]);
1091: if (tickX1 > area.getMinX()) {
1092: g2.drawString(
1093: UNITS[this.units], tickX1, (int) (area.getMinY() + 20)
1094: );
1095: }
1096:
1097:
1098: g2.setStroke(this.thermometerStroke);
1099: g2.draw(outerThermometer);
1100: g2.draw(innerThermometer);
1101:
1102: drawOutline(g2, area);
1103: }
1104:
1105:
1112: public void zoom(double percent) {
1113:
1114: }
1115:
1116:
1121: public String getPlotType() {
1122: return localizationResources.getString("Thermometer_Plot");
1123: }
1124:
1125:
1130: public void datasetChanged(DatasetChangeEvent event) {
1131: Number vn = this.dataset.getValue();
1132: if (vn != null) {
1133: double value = vn.doubleValue();
1134: if (inSubrange(NORMAL, value)) {
1135: this.subrange = NORMAL;
1136: }
1137: else if (inSubrange(WARNING, value)) {
1138: this.subrange = WARNING;
1139: }
1140: else if (inSubrange(CRITICAL, value)) {
1141: this.subrange = CRITICAL;
1142: }
1143: else {
1144: this.subrange = -1;
1145: }
1146: setAxisRange();
1147: }
1148: super.datasetChanged(event);
1149: }
1150:
1151:
1158: public Number getMinimumVerticalDataValue() {
1159: return new Double(this.lowerBound);
1160: }
1161:
1162:
1169: public Number getMaximumVerticalDataValue() {
1170: return new Double(this.upperBound);
1171: }
1172:
1173:
1180: public Range getDataRange(ValueAxis axis) {
1181: return new Range(this.lowerBound, this.upperBound);
1182: }
1183:
1184:
1187: protected void setAxisRange() {
1188: if ((this.subrange >= 0) && (this.followDataInSubranges)) {
1189: this.rangeAxis.setRange(
1190: new Range(this.subrangeInfo[this.subrange][DISPLAY_LOW],
1191: this.subrangeInfo[this.subrange][DISPLAY_HIGH])
1192: );
1193: }
1194: else {
1195: this.rangeAxis.setRange(this.lowerBound, this.upperBound);
1196: }
1197: }
1198:
1199:
1204: public LegendItemCollection getLegendItems() {
1205: return null;
1206: }
1207:
1208:
1213: public PlotOrientation getOrientation() {
1214: return PlotOrientation.VERTICAL;
1215: }
1216:
1217:
1225: protected static boolean isValidNumber(double d) {
1226: return (!(Double.isNaN(d) || Double.isInfinite(d)));
1227: }
1228:
1229:
1237: private boolean inSubrange(int subrange, double value) {
1238: return (value > this.subrangeInfo[subrange][RANGE_LOW]
1239: && value <= this.subrangeInfo[subrange][RANGE_HIGH]);
1240: }
1241:
1242:
1247: private Paint getCurrentPaint() {
1248:
1249: Paint result = this.mercuryPaint;
1250: if (this.useSubrangePaint) {
1251: double value = this.dataset.getValue().doubleValue();
1252: if (inSubrange(NORMAL, value)) {
1253: result = this.subrangePaint[NORMAL];
1254: }
1255: else if (inSubrange(WARNING, value)) {
1256: result = this.subrangePaint[WARNING];
1257: }
1258: else if (inSubrange(CRITICAL, value)) {
1259: result = this.subrangePaint[CRITICAL];
1260: }
1261: }
1262: return result;
1263: }
1264:
1265:
1273: public boolean equals(Object obj) {
1274: if (obj == this) {
1275: return true;
1276: }
1277: if (!(obj instanceof ThermometerPlot)) {
1278: return false;
1279: }
1280: ThermometerPlot that = (ThermometerPlot) obj;
1281: if (!super.equals(obj)) {
1282: return false;
1283: }
1284: if (!ObjectUtilities.equal(this.rangeAxis, that.rangeAxis)) {
1285: return false;
1286: }
1287: if (this.axisLocation != that.axisLocation) {
1288: return false;
1289: }
1290: if (this.lowerBound != that.lowerBound) {
1291: return false;
1292: }
1293: if (this.upperBound != that.upperBound) {
1294: return false;
1295: }
1296: if (!ObjectUtilities.equal(this.padding, that.padding)) {
1297: return false;
1298: }
1299: if (!ObjectUtilities.equal(
1300: this.thermometerStroke, that.thermometerStroke
1301: )) {
1302: return false;
1303: }
1304: if (!PaintUtilities.equal(
1305: this.thermometerPaint, that.thermometerPaint
1306: )) {
1307: return false;
1308: }
1309: if (this.units != that.units) {
1310: return false;
1311: }
1312: if (this.valueLocation != that.valueLocation) {
1313: return false;
1314: }
1315: if (!ObjectUtilities.equal(this.valueFont, that.valueFont)) {
1316: return false;
1317: }
1318: if (!PaintUtilities.equal(this.valuePaint, that.valuePaint)) {
1319: return false;
1320: }
1321: if (!ObjectUtilities.equal(this.valueFormat, that.valueFormat)) {
1322: return false;
1323: }
1324: if (!PaintUtilities.equal(this.mercuryPaint, that.mercuryPaint)) {
1325: return false;
1326: }
1327: if (this.showValueLines != that.showValueLines) {
1328: return false;
1329: }
1330: if (this.subrange != that.subrange) {
1331: return false;
1332: }
1333: if (this.followDataInSubranges != that.followDataInSubranges) {
1334: return false;
1335: }
1336: if (!equal(this.subrangeInfo, that.subrangeInfo)) {
1337: return false;
1338: }
1339: if (this.useSubrangePaint != that.useSubrangePaint) {
1340: return false;
1341: }
1342: for (int i = 0; i < this.subrangePaint.length; i++) {
1343: if (!PaintUtilities.equal(this.subrangePaint[i],
1344: that.subrangePaint[i])) {
1345: return false;
1346: }
1347: }
1348: return true;
1349: }
1350:
1351:
1359: private static boolean equal(double[][] array1, double[][] array2) {
1360: if (array1 == null) {
1361: return (array2 == null);
1362: }
1363: if (array2 == null) {
1364: return false;
1365: }
1366: if (array1.length != array2.length) {
1367: return false;
1368: }
1369: for (int i = 0; i < array1.length; i++) {
1370: if (!Arrays.equals(array1[i], array2[i])) {
1371: return false;
1372: }
1373: }
1374: return true;
1375: }
1376:
1377:
1384: public Object clone() throws CloneNotSupportedException {
1385:
1386: ThermometerPlot clone = (ThermometerPlot) super.clone();
1387:
1388: if (clone.dataset != null) {
1389: clone.dataset.addChangeListener(clone);
1390: }
1391: clone.rangeAxis = (ValueAxis) ObjectUtilities.clone(this.rangeAxis);
1392: if (clone.rangeAxis != null) {
1393: clone.rangeAxis.setPlot(clone);
1394: clone.rangeAxis.addChangeListener(clone);
1395: }
1396: clone.valueFormat = (NumberFormat) this.valueFormat.clone();
1397: clone.subrangePaint = (Paint[]) this.subrangePaint.clone();
1398:
1399: return clone;
1400:
1401: }
1402:
1403:
1410: private void writeObject(ObjectOutputStream stream) throws IOException {
1411: stream.defaultWriteObject();
1412: SerialUtilities.writeStroke(this.thermometerStroke, stream);
1413: SerialUtilities.writePaint(this.thermometerPaint, stream);
1414: SerialUtilities.writePaint(this.valuePaint, stream);
1415: SerialUtilities.writePaint(this.mercuryPaint, stream);
1416: SerialUtilities.writeStroke(this.subrangeIndicatorStroke, stream);
1417: SerialUtilities.writeStroke(this.rangeIndicatorStroke, stream);
1418: }
1419:
1420:
1428: private void readObject(ObjectInputStream stream) throws IOException,
1429: ClassNotFoundException {
1430: stream.defaultReadObject();
1431: this.thermometerStroke = SerialUtilities.readStroke(stream);
1432: this.thermometerPaint = SerialUtilities.readPaint(stream);
1433: this.valuePaint = SerialUtilities.readPaint(stream);
1434: this.mercuryPaint = SerialUtilities.readPaint(stream);
1435: this.subrangeIndicatorStroke = SerialUtilities.readStroke(stream);
1436: this.rangeIndicatorStroke = SerialUtilities.readStroke(stream);
1437:
1438: if (this.rangeAxis != null) {
1439: this.rangeAxis.addChangeListener(this);
1440: }
1441: }
1442:
1443:
1450: public void zoomDomainAxes(double factor, PlotRenderingInfo state,
1451: Point2D source) {
1452:
1453: }
1454:
1455:
1462: public void zoomRangeAxes(double factor, PlotRenderingInfo state,
1463: Point2D source) {
1464: this.rangeAxis.resizeRange(factor);
1465: }
1466:
1467:
1475: public void zoomDomainAxes(double lowerPercent, double upperPercent,
1476: PlotRenderingInfo state, Point2D source) {
1477:
1478: }
1479:
1480:
1488: public void zoomRangeAxes(double lowerPercent, double upperPercent,
1489: PlotRenderingInfo state, Point2D source) {
1490: this.rangeAxis.zoomRange(lowerPercent, upperPercent);
1491: }
1492:
1493:
1498: public boolean isDomainZoomable() {
1499: return false;
1500: }
1501:
1502:
1507: public boolean isRangeZoomable() {
1508: return true;
1509: }
1510:
1511: }