1:
79:
80: package ;
81:
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: import ;
102: import ;
103:
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: import ;
117: import ;
118:
119:
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(UnitType.RELATIVE, 0.05, 0.05, 0.05,
327: 0.05);
328: this.dataset = dataset;
329: if (dataset != null) {
330: dataset.addChangeListener(this);
331: }
332: NumberAxis axis = new NumberAxis(null);
333: axis.setStandardTickUnits(NumberAxis.createIntegerTickUnits());
334: axis.setAxisLineVisible(false);
335:
336: setRangeAxis(axis);
337: setAxisRange();
338: }
339:
340:
345: public ValueDataset getDataset() {
346: return this.dataset;
347: }
348:
349:
355: public void setDataset(ValueDataset dataset) {
356:
357:
358:
359: ValueDataset existing = this.dataset;
360: if (existing != null) {
361: existing.removeChangeListener(this);
362: }
363:
364:
365: this.dataset = dataset;
366: if (dataset != null) {
367: setDatasetGroup(dataset.getGroup());
368: dataset.addChangeListener(this);
369: }
370:
371:
372: DatasetChangeEvent event = new DatasetChangeEvent(this, dataset);
373: datasetChanged(event);
374:
375: }
376:
377:
382: public ValueAxis getRangeAxis() {
383: return this.rangeAxis;
384: }
385:
386:
391: public void setRangeAxis(ValueAxis axis) {
392:
393: if (axis != null) {
394: axis.setPlot(this);
395: axis.addChangeListener(this);
396: }
397:
398:
399: if (this.rangeAxis != null) {
400: this.rangeAxis.removeChangeListener(this);
401: }
402:
403: this.rangeAxis = axis;
404:
405: }
406:
407:
414: public double getLowerBound() {
415: return this.lowerBound;
416: }
417:
418:
423: public void setLowerBound(double lower) {
424: this.lowerBound = lower;
425: setAxisRange();
426: }
427:
428:
434: public double getUpperBound() {
435: return this.upperBound;
436: }
437:
438:
443: public void setUpperBound(double upper) {
444: this.upperBound = upper;
445: setAxisRange();
446: }
447:
448:
454: public void setRange(double lower, double upper) {
455: this.lowerBound = lower;
456: this.upperBound = upper;
457: setAxisRange();
458: }
459:
460:
466: public RectangleInsets getPadding() {
467: return this.padding;
468: }
469:
470:
475: public void setPadding(RectangleInsets padding) {
476: this.padding = padding;
477: notifyListeners(new PlotChangeEvent(this));
478: }
479:
480:
485: public Stroke getThermometerStroke() {
486: return this.thermometerStroke;
487: }
488:
489:
494: public void setThermometerStroke(Stroke s) {
495: if (s != null) {
496: this.thermometerStroke = s;
497: notifyListeners(new PlotChangeEvent(this));
498: }
499: }
500:
501:
506: public Paint getThermometerPaint() {
507: return this.thermometerPaint;
508: }
509:
510:
515: public void setThermometerPaint(Paint paint) {
516: if (paint != null) {
517: this.thermometerPaint = paint;
518: notifyListeners(new PlotChangeEvent(this));
519: }
520: }
521:
522:
527: public int getUnits() {
528: return this.units;
529: }
530:
531:
545: public void setUnits(int u) {
546: if ((u >= 0) && (u < UNITS.length)) {
547: if (this.units != u) {
548: this.units = u;
549: notifyListeners(new PlotChangeEvent(this));
550: }
551: }
552: }
553:
554:
559: public void setUnits(String u) {
560: if (u == null) {
561: return;
562: }
563:
564: u = u.toUpperCase().trim();
565: for (int i = 0; i < UNITS.length; ++i) {
566: if (u.equals(UNITS[i].toUpperCase().trim())) {
567: setUnits(i);
568: i = UNITS.length;
569: }
570: }
571: }
572:
573:
578: public int getValueLocation() {
579: return this.valueLocation;
580: }
581:
582:
593: public void setValueLocation(int location) {
594: if ((location >= 0) && (location < 4)) {
595: this.valueLocation = location;
596: notifyListeners(new PlotChangeEvent(this));
597: }
598: else {
599: throw new IllegalArgumentException("Location not recognised.");
600: }
601: }
602:
603:
614: public void setAxisLocation(int location) {
615: if ((location >= 0) && (location < 3)) {
616: this.axisLocation = location;
617: notifyListeners(new PlotChangeEvent(this));
618: }
619: else {
620: throw new IllegalArgumentException("Location not recognised.");
621: }
622: }
623:
624:
629: public int getAxisLocation() {
630: return this.axisLocation;
631: }
632:
633:
638: public Font getValueFont() {
639: return this.valueFont;
640: }
641:
642:
647: public void setValueFont(Font f) {
648: if ((f != null) && (!this.valueFont.equals(f))) {
649: this.valueFont = f;
650: notifyListeners(new PlotChangeEvent(this));
651: }
652: }
653:
654:
659: public Paint getValuePaint() {
660: return this.valuePaint;
661: }
662:
663:
668: public void setValuePaint(Paint p) {
669: if ((p != null) && (!this.valuePaint.equals(p))) {
670: this.valuePaint = p;
671: notifyListeners(new PlotChangeEvent(this));
672: }
673: }
674:
675:
680: public void setValueFormat(NumberFormat formatter) {
681: if (formatter != null) {
682: this.valueFormat = formatter;
683: notifyListeners(new PlotChangeEvent(this));
684: }
685: }
686:
687:
692: public Paint getMercuryPaint() {
693: return this.mercuryPaint;
694: }
695:
696:
701: public void setMercuryPaint(Paint paint) {
702: this.mercuryPaint = paint;
703: notifyListeners(new PlotChangeEvent(this));
704: }
705:
706:
711: public boolean getShowValueLines() {
712: return this.showValueLines;
713: }
714:
715:
720: public void setShowValueLines(boolean b) {
721: this.showValueLines = b;
722: notifyListeners(new PlotChangeEvent(this));
723: }
724:
725:
732: public void setSubrangeInfo(int range, double low, double hi) {
733: setSubrangeInfo(range, low, hi, low, hi);
734: }
735:
736:
745: public void setSubrangeInfo(int range,
746: double rangeLow, double rangeHigh,
747: double displayLow, double displayHigh) {
748:
749: if ((range >= 0) && (range < 3)) {
750: setSubrange(range, rangeLow, rangeHigh);
751: setDisplayRange(range, displayLow, displayHigh);
752: setAxisRange();
753: notifyListeners(new PlotChangeEvent(this));
754: }
755:
756: }
757:
758:
765: public void setSubrange(int range, double low, double high) {
766: if ((range >= 0) && (range < 3)) {
767: this.subrangeInfo[range][RANGE_HIGH] = high;
768: this.subrangeInfo[range][RANGE_LOW] = low;
769: }
770: }
771:
772:
779: public void setDisplayRange(int range, double low, double high) {
780:
781: if ((range >= 0) && (range < this.subrangeInfo.length)
782: && isValidNumber(high) && isValidNumber(low)) {
783:
784: if (high > low) {
785: this.subrangeInfo[range][DISPLAY_HIGH] = high;
786: this.subrangeInfo[range][DISPLAY_LOW] = low;
787: }
788: else {
789: this.subrangeInfo[range][DISPLAY_HIGH] = low;
790: this.subrangeInfo[range][DISPLAY_LOW] = high;
791: }
792:
793: }
794:
795: }
796:
797:
804: public Paint getSubrangePaint(int range) {
805: if ((range >= 0) && (range < this.subrangePaint.length)) {
806: return this.subrangePaint[range];
807: }
808: else {
809: return this.mercuryPaint;
810: }
811: }
812:
813:
819: public void setSubrangePaint(int range, Paint paint) {
820: if ((range >= 0)
821: && (range < this.subrangePaint.length) && (paint != null)) {
822: this.subrangePaint[range] = paint;
823: notifyListeners(new PlotChangeEvent(this));
824: }
825: }
826:
827:
833: public boolean getFollowDataInSubranges() {
834: return this.followDataInSubranges;
835: }
836:
837:
843: public void setFollowDataInSubranges(boolean flag) {
844: this.followDataInSubranges = flag;
845: notifyListeners(new PlotChangeEvent(this));
846: }
847:
848:
854: public boolean getUseSubrangePaint() {
855: return this.useSubrangePaint;
856: }
857:
858:
863: public void setUseSubrangePaint(boolean flag) {
864: this.useSubrangePaint = flag;
865: notifyListeners(new PlotChangeEvent(this));
866: }
867:
868:
878: public void draw(Graphics2D g2, Rectangle2D area, Point2D anchor,
879: PlotState parentState,
880: PlotRenderingInfo info) {
881:
882: RoundRectangle2D outerStem = new RoundRectangle2D.Double();
883: RoundRectangle2D innerStem = new RoundRectangle2D.Double();
884: RoundRectangle2D mercuryStem = new RoundRectangle2D.Double();
885: Ellipse2D outerBulb = new Ellipse2D.Double();
886: Ellipse2D innerBulb = new Ellipse2D.Double();
887: String temp = null;
888: FontMetrics metrics = null;
889: if (info != null) {
890: info.setPlotArea(area);
891: }
892:
893:
894: RectangleInsets insets = getInsets();
895: insets.trim(area);
896: drawBackground(g2, area);
897:
898:
899: Rectangle2D interior = (Rectangle2D) area.clone();
900: this.padding.trim(interior);
901: int midX = (int) (interior.getX() + (interior.getWidth() / 2));
902: int midY = (int) (interior.getY() + (interior.getHeight() / 2));
903: int stemTop = (int) (interior.getMinY() + BULB_RADIUS);
904: int stemBottom = (int) (interior.getMaxY() - BULB_DIAMETER);
905: Rectangle2D dataArea = new Rectangle2D.Double(midX - COLUMN_RADIUS,
906: stemTop, COLUMN_RADIUS, stemBottom - stemTop);
907:
908: outerBulb.setFrame(midX - BULB_RADIUS, stemBottom, BULB_DIAMETER,
909: BULB_DIAMETER);
910:
911: outerStem.setRoundRect(midX - COLUMN_RADIUS, interior.getMinY(),
912: COLUMN_DIAMETER, stemBottom + BULB_DIAMETER - stemTop,
913: COLUMN_DIAMETER, COLUMN_DIAMETER);
914:
915: Area outerThermometer = new Area(outerBulb);
916: Area tempArea = new Area(outerStem);
917: outerThermometer.add(tempArea);
918:
919: innerBulb.setFrame(midX - BULB_RADIUS + GAP_RADIUS,
920: stemBottom + GAP_RADIUS, BULB_DIAMETER - GAP_DIAMETER,
921: BULB_DIAMETER - GAP_DIAMETER);
922:
923: innerStem.setRoundRect(midX - COLUMN_RADIUS + GAP_RADIUS,
924: interior.getMinY() + GAP_RADIUS, COLUMN_DIAMETER - GAP_DIAMETER,
925: stemBottom + BULB_DIAMETER - GAP_DIAMETER - stemTop,
926: COLUMN_DIAMETER - GAP_DIAMETER, COLUMN_DIAMETER - GAP_DIAMETER);
927:
928: Area innerThermometer = new Area(innerBulb);
929: tempArea = new Area(innerStem);
930: innerThermometer.add(tempArea);
931:
932: if ((this.dataset != null) && (this.dataset.getValue() != null)) {
933: double current = this.dataset.getValue().doubleValue();
934: double ds = this.rangeAxis.valueToJava2D(current, dataArea,
935: RectangleEdge.LEFT);
936:
937: int i = COLUMN_DIAMETER - GAP_DIAMETER;
938: int j = COLUMN_RADIUS - GAP_RADIUS;
939: int l = (i / 2);
940: int k = (int) Math.round(ds);
941: if (k < (GAP_RADIUS + interior.getMinY())) {
942: k = (int) (GAP_RADIUS + interior.getMinY());
943: l = BULB_RADIUS;
944: }
945:
946: Area mercury = new Area(innerBulb);
947:
948: if (k < (stemBottom + BULB_RADIUS)) {
949: mercuryStem.setRoundRect(midX - j, k, i,
950: (stemBottom + BULB_RADIUS) - k, l, l);
951: tempArea = new Area(mercuryStem);
952: mercury.add(tempArea);
953: }
954:
955: g2.setPaint(getCurrentPaint());
956: g2.fill(mercury);
957:
958:
959: if (this.subrangeIndicatorsVisible) {
960: g2.setStroke(this.subrangeIndicatorStroke);
961: Range range = this.rangeAxis.getRange();
962:
963:
964: double value = this.subrangeInfo[NORMAL][RANGE_LOW];
965: if (range.contains(value)) {
966: double x = midX + COLUMN_RADIUS + 2;
967: double y = this.rangeAxis.valueToJava2D(value, dataArea,
968: RectangleEdge.LEFT);
969: Line2D line = new Line2D.Double(x, y, x + 10, y);
970: g2.setPaint(this.subrangePaint[NORMAL]);
971: g2.draw(line);
972: }
973:
974:
975: value = this.subrangeInfo[WARNING][RANGE_LOW];
976: if (range.contains(value)) {
977: double x = midX + COLUMN_RADIUS + 2;
978: double y = this.rangeAxis.valueToJava2D(value, dataArea,
979: RectangleEdge.LEFT);
980: Line2D line = new Line2D.Double(x, y, x + 10, y);
981: g2.setPaint(this.subrangePaint[WARNING]);
982: g2.draw(line);
983: }
984:
985:
986: value = this.subrangeInfo[CRITICAL][RANGE_LOW];
987: if (range.contains(value)) {
988: double x = midX + COLUMN_RADIUS + 2;
989: double y = this.rangeAxis.valueToJava2D(value, dataArea,
990: RectangleEdge.LEFT);
991: Line2D line = new Line2D.Double(x, y, x + 10, y);
992: g2.setPaint(this.subrangePaint[CRITICAL]);
993: g2.draw(line);
994: }
995: }
996:
997:
998: if ((this.rangeAxis != null) && (this.axisLocation != NONE)) {
999: int drawWidth = AXIS_GAP;
1000: if (this.showValueLines) {
1001: drawWidth += COLUMN_DIAMETER;
1002: }
1003: Rectangle2D drawArea;
1004: double cursor = 0;
1005:
1006: switch (this.axisLocation) {
1007: case RIGHT:
1008: cursor = midX + COLUMN_RADIUS;
1009: drawArea = new Rectangle2D.Double(cursor,
1010: stemTop, drawWidth, (stemBottom - stemTop + 1));
1011: this.rangeAxis.draw(g2, cursor, area, drawArea,
1012: RectangleEdge.RIGHT, null);
1013: break;
1014:
1015: case LEFT:
1016: default:
1017:
1018: cursor = midX - COLUMN_RADIUS;
1019: drawArea = new Rectangle2D.Double(cursor, stemTop,
1020: drawWidth, (stemBottom - stemTop + 1));
1021: this.rangeAxis.draw(g2, cursor, area, drawArea,
1022: RectangleEdge.LEFT, null);
1023: break;
1024: }
1025:
1026: }
1027:
1028:
1029: g2.setFont(this.valueFont);
1030: g2.setPaint(this.valuePaint);
1031: metrics = g2.getFontMetrics();
1032: switch (this.valueLocation) {
1033: case RIGHT:
1034: g2.drawString(this.valueFormat.format(current),
1035: midX + COLUMN_RADIUS + GAP_RADIUS, midY);
1036: break;
1037: case LEFT:
1038: String valueString = this.valueFormat.format(current);
1039: int stringWidth = metrics.stringWidth(valueString);
1040: g2.drawString(valueString, midX - COLUMN_RADIUS
1041: - GAP_RADIUS - stringWidth, midY);
1042: break;
1043: case BULB:
1044: temp = this.valueFormat.format(current);
1045: i = metrics.stringWidth(temp) / 2;
1046: g2.drawString(temp, midX - i,
1047: stemBottom + BULB_RADIUS + GAP_RADIUS);
1048: break;
1049: default:
1050: }
1051:
1052: }
1053:
1054: g2.setPaint(this.thermometerPaint);
1055: g2.setFont(this.valueFont);
1056:
1057:
1058: metrics = g2.getFontMetrics();
1059: int tickX1 = midX - COLUMN_RADIUS - GAP_DIAMETER
1060: - metrics.stringWidth(UNITS[this.units]);
1061: if (tickX1 > area.getMinX()) {
1062: g2.drawString(UNITS[this.units], tickX1,
1063: (int) (area.getMinY() + 20));
1064: }
1065:
1066:
1067: g2.setStroke(this.thermometerStroke);
1068: g2.draw(outerThermometer);
1069: g2.draw(innerThermometer);
1070:
1071: drawOutline(g2, area);
1072: }
1073:
1074:
1081: public void zoom(double percent) {
1082:
1083: }
1084:
1085:
1090: public String getPlotType() {
1091: return localizationResources.getString("Thermometer_Plot");
1092: }
1093:
1094:
1099: public void datasetChanged(DatasetChangeEvent event) {
1100: Number vn = this.dataset.getValue();
1101: if (vn != null) {
1102: double value = vn.doubleValue();
1103: if (inSubrange(NORMAL, value)) {
1104: this.subrange = NORMAL;
1105: }
1106: else if (inSubrange(WARNING, value)) {
1107: this.subrange = WARNING;
1108: }
1109: else if (inSubrange(CRITICAL, value)) {
1110: this.subrange = CRITICAL;
1111: }
1112: else {
1113: this.subrange = -1;
1114: }
1115: setAxisRange();
1116: }
1117: super.datasetChanged(event);
1118: }
1119:
1120:
1127: public Number getMinimumVerticalDataValue() {
1128: return new Double(this.lowerBound);
1129: }
1130:
1131:
1138: public Number getMaximumVerticalDataValue() {
1139: return new Double(this.upperBound);
1140: }
1141:
1142:
1149: public Range getDataRange(ValueAxis axis) {
1150: return new Range(this.lowerBound, this.upperBound);
1151: }
1152:
1153:
1156: protected void setAxisRange() {
1157: if ((this.subrange >= 0) && (this.followDataInSubranges)) {
1158: this.rangeAxis.setRange(
1159: new Range(this.subrangeInfo[this.subrange][DISPLAY_LOW],
1160: this.subrangeInfo[this.subrange][DISPLAY_HIGH]));
1161: }
1162: else {
1163: this.rangeAxis.setRange(this.lowerBound, this.upperBound);
1164: }
1165: }
1166:
1167:
1172: public LegendItemCollection getLegendItems() {
1173: return null;
1174: }
1175:
1176:
1181: public PlotOrientation getOrientation() {
1182: return PlotOrientation.VERTICAL;
1183: }
1184:
1185:
1193: protected static boolean isValidNumber(double d) {
1194: return (!(Double.isNaN(d) || Double.isInfinite(d)));
1195: }
1196:
1197:
1205: private boolean inSubrange(int subrange, double value) {
1206: return (value > this.subrangeInfo[subrange][RANGE_LOW]
1207: && value <= this.subrangeInfo[subrange][RANGE_HIGH]);
1208: }
1209:
1210:
1215: private Paint getCurrentPaint() {
1216:
1217: Paint result = this.mercuryPaint;
1218: if (this.useSubrangePaint) {
1219: double value = this.dataset.getValue().doubleValue();
1220: if (inSubrange(NORMAL, value)) {
1221: result = this.subrangePaint[NORMAL];
1222: }
1223: else if (inSubrange(WARNING, value)) {
1224: result = this.subrangePaint[WARNING];
1225: }
1226: else if (inSubrange(CRITICAL, value)) {
1227: result = this.subrangePaint[CRITICAL];
1228: }
1229: }
1230: return result;
1231: }
1232:
1233:
1241: public boolean equals(Object obj) {
1242: if (obj == this) {
1243: return true;
1244: }
1245: if (!(obj instanceof ThermometerPlot)) {
1246: return false;
1247: }
1248: ThermometerPlot that = (ThermometerPlot) obj;
1249: if (!super.equals(obj)) {
1250: return false;
1251: }
1252: if (!ObjectUtilities.equal(this.rangeAxis, that.rangeAxis)) {
1253: return false;
1254: }
1255: if (this.axisLocation != that.axisLocation) {
1256: return false;
1257: }
1258: if (this.lowerBound != that.lowerBound) {
1259: return false;
1260: }
1261: if (this.upperBound != that.upperBound) {
1262: return false;
1263: }
1264: if (!ObjectUtilities.equal(this.padding, that.padding)) {
1265: return false;
1266: }
1267: if (!ObjectUtilities.equal(this.thermometerStroke,
1268: that.thermometerStroke)) {
1269: return false;
1270: }
1271: if (!PaintUtilities.equal(this.thermometerPaint,
1272: that.thermometerPaint)) {
1273: return false;
1274: }
1275: if (this.units != that.units) {
1276: return false;
1277: }
1278: if (this.valueLocation != that.valueLocation) {
1279: return false;
1280: }
1281: if (!ObjectUtilities.equal(this.valueFont, that.valueFont)) {
1282: return false;
1283: }
1284: if (!PaintUtilities.equal(this.valuePaint, that.valuePaint)) {
1285: return false;
1286: }
1287: if (!ObjectUtilities.equal(this.valueFormat, that.valueFormat)) {
1288: return false;
1289: }
1290: if (!PaintUtilities.equal(this.mercuryPaint, that.mercuryPaint)) {
1291: return false;
1292: }
1293: if (this.showValueLines != that.showValueLines) {
1294: return false;
1295: }
1296: if (this.subrange != that.subrange) {
1297: return false;
1298: }
1299: if (this.followDataInSubranges != that.followDataInSubranges) {
1300: return false;
1301: }
1302: if (!equal(this.subrangeInfo, that.subrangeInfo)) {
1303: return false;
1304: }
1305: if (this.useSubrangePaint != that.useSubrangePaint) {
1306: return false;
1307: }
1308: for (int i = 0; i < this.subrangePaint.length; i++) {
1309: if (!PaintUtilities.equal(this.subrangePaint[i],
1310: that.subrangePaint[i])) {
1311: return false;
1312: }
1313: }
1314: return true;
1315: }
1316:
1317:
1325: private static boolean equal(double[][] array1, double[][] array2) {
1326: if (array1 == null) {
1327: return (array2 == null);
1328: }
1329: if (array2 == null) {
1330: return false;
1331: }
1332: if (array1.length != array2.length) {
1333: return false;
1334: }
1335: for (int i = 0; i < array1.length; i++) {
1336: if (!Arrays.equals(array1[i], array2[i])) {
1337: return false;
1338: }
1339: }
1340: return true;
1341: }
1342:
1343:
1350: public Object clone() throws CloneNotSupportedException {
1351:
1352: ThermometerPlot clone = (ThermometerPlot) super.clone();
1353:
1354: if (clone.dataset != null) {
1355: clone.dataset.addChangeListener(clone);
1356: }
1357: clone.rangeAxis = (ValueAxis) ObjectUtilities.clone(this.rangeAxis);
1358: if (clone.rangeAxis != null) {
1359: clone.rangeAxis.setPlot(clone);
1360: clone.rangeAxis.addChangeListener(clone);
1361: }
1362: clone.valueFormat = (NumberFormat) this.valueFormat.clone();
1363: clone.subrangePaint = (Paint[]) this.subrangePaint.clone();
1364:
1365: return clone;
1366:
1367: }
1368:
1369:
1376: private void writeObject(ObjectOutputStream stream) throws IOException {
1377: stream.defaultWriteObject();
1378: SerialUtilities.writeStroke(this.thermometerStroke, stream);
1379: SerialUtilities.writePaint(this.thermometerPaint, stream);
1380: SerialUtilities.writePaint(this.valuePaint, stream);
1381: SerialUtilities.writePaint(this.mercuryPaint, stream);
1382: SerialUtilities.writeStroke(this.subrangeIndicatorStroke, stream);
1383: SerialUtilities.writeStroke(this.rangeIndicatorStroke, stream);
1384: }
1385:
1386:
1394: private void readObject(ObjectInputStream stream) throws IOException,
1395: ClassNotFoundException {
1396: stream.defaultReadObject();
1397: this.thermometerStroke = SerialUtilities.readStroke(stream);
1398: this.thermometerPaint = SerialUtilities.readPaint(stream);
1399: this.valuePaint = SerialUtilities.readPaint(stream);
1400: this.mercuryPaint = SerialUtilities.readPaint(stream);
1401: this.subrangeIndicatorStroke = SerialUtilities.readStroke(stream);
1402: this.rangeIndicatorStroke = SerialUtilities.readStroke(stream);
1403:
1404: if (this.rangeAxis != null) {
1405: this.rangeAxis.addChangeListener(this);
1406: }
1407: }
1408:
1409:
1416: public void zoomDomainAxes(double factor, PlotRenderingInfo state,
1417: Point2D source) {
1418:
1419: }
1420:
1421:
1428: public void zoomRangeAxes(double factor, PlotRenderingInfo state,
1429: Point2D source) {
1430: this.rangeAxis.resizeRange(factor);
1431: }
1432:
1433:
1441: public void zoomDomainAxes(double lowerPercent, double upperPercent,
1442: PlotRenderingInfo state, Point2D source) {
1443:
1444: }
1445:
1446:
1454: public void zoomRangeAxes(double lowerPercent, double upperPercent,
1455: PlotRenderingInfo state, Point2D source) {
1456: this.rangeAxis.zoomRange(lowerPercent, upperPercent);
1457: }
1458:
1459:
1464: public boolean isDomainZoomable() {
1465: return false;
1466: }
1467:
1468:
1473: public boolean isRangeZoomable() {
1474: return true;
1475: }
1476:
1477: }