1:
84:
85: package ;
86:
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: import ;
104: import ;
105: import ;
106: import ;
107: import ;
108: import ;
109: import ;
110: import ;
111: import ;
112:
113: import ;
114: import ;
115: import ;
116: import ;
117: import ;
118: import ;
119: import ;
120: import ;
121: import ;
122: import ;
123: import ;
124: import ;
125:
126:
131: public class MeterPlot extends Plot implements Serializable, Cloneable {
132:
133:
134: private static final long serialVersionUID = 2987472457734470962L;
135:
136:
137: static final Paint DEFAULT_DIAL_BACKGROUND_PAINT = Color.black;
138:
139:
140: static final Paint DEFAULT_NEEDLE_PAINT = Color.green;
141:
142:
143: static final Font DEFAULT_VALUE_FONT = new Font("SansSerif", Font.BOLD, 12);
144:
145:
146: static final Paint DEFAULT_VALUE_PAINT = Color.yellow;
147:
148:
149: public static final int DEFAULT_METER_ANGLE = 270;
150:
151:
152: public static final float DEFAULT_BORDER_SIZE = 3f;
153:
154:
155: public static final float DEFAULT_CIRCLE_SIZE = 10f;
156:
157:
158: public static final Font DEFAULT_LABEL_FONT = new Font("SansSerif",
159: Font.BOLD, 10);
160:
161:
162: private ValueDataset dataset;
163:
164:
165: private DialShape shape;
166:
167:
168: private int meterAngle;
169:
170:
171: private Range range;
172:
173:
174: private double tickSize;
175:
176:
177: private transient Paint tickPaint;
178:
179:
180: private String units;
181:
182:
183: private Font valueFont;
184:
185:
186: private transient Paint valuePaint;
187:
188:
189: private boolean drawBorder;
190:
191:
192: private transient Paint dialOutlinePaint;
193:
194:
195: private transient Paint dialBackgroundPaint;
196:
197:
198: private transient Paint needlePaint;
199:
200:
201: private boolean tickLabelsVisible;
202:
203:
204: private Font tickLabelFont;
205:
206:
207: private transient Paint tickLabelPaint;
208:
209:
210: private NumberFormat tickLabelFormat;
211:
212:
213: protected static ResourceBundle localizationResources =
214: ResourceBundle.getBundle("org.jfree.chart.plot.LocalizationBundle");
215:
216:
220: private List intervals;
221:
222:
226: public MeterPlot() {
227: this(null);
228: }
229:
230:
235: public MeterPlot(ValueDataset dataset) {
236: super();
237: this.shape = DialShape.CIRCLE;
238: this.meterAngle = DEFAULT_METER_ANGLE;
239: this.range = new Range(0.0, 100.0);
240: this.tickSize = 10.0;
241: this.tickPaint = Color.white;
242: this.units = "Units";
243: this.needlePaint = MeterPlot.DEFAULT_NEEDLE_PAINT;
244: this.tickLabelsVisible = true;
245: this.tickLabelFont = MeterPlot.DEFAULT_LABEL_FONT;
246: this.tickLabelPaint = Color.black;
247: this.tickLabelFormat = NumberFormat.getInstance();
248: this.valueFont = MeterPlot.DEFAULT_VALUE_FONT;
249: this.valuePaint = MeterPlot.DEFAULT_VALUE_PAINT;
250: this.dialBackgroundPaint = MeterPlot.DEFAULT_DIAL_BACKGROUND_PAINT;
251: this.intervals = new java.util.ArrayList();
252: setDataset(dataset);
253: }
254:
255:
262: public DialShape getDialShape() {
263: return this.shape;
264: }
265:
266:
274: public void setDialShape(DialShape shape) {
275: if (shape == null) {
276: throw new IllegalArgumentException("Null 'shape' argument.");
277: }
278: this.shape = shape;
279: fireChangeEvent();
280: }
281:
282:
290: public int getMeterAngle() {
291: return this.meterAngle;
292: }
293:
294:
302: public void setMeterAngle(int angle) {
303: if (angle < 1 || angle > 360) {
304: throw new IllegalArgumentException("Invalid 'angle' (" + angle
305: + ")");
306: }
307: this.meterAngle = angle;
308: fireChangeEvent();
309: }
310:
311:
318: public Range getRange() {
319: return this.range;
320: }
321:
322:
331: public void setRange(Range range) {
332: if (range == null) {
333: throw new IllegalArgumentException("Null 'range' argument.");
334: }
335: if (!(range.getLength() > 0.0)) {
336: throw new IllegalArgumentException(
337: "Range length must be positive.");
338: }
339: this.range = range;
340: fireChangeEvent();
341: }
342:
343:
350: public double getTickSize() {
351: return this.tickSize;
352: }
353:
354:
362: public void setTickSize(double size) {
363: if (size <= 0) {
364: throw new IllegalArgumentException("Requires 'size' > 0.");
365: }
366: this.tickSize = size;
367: fireChangeEvent();
368: }
369:
370:
378: public Paint getTickPaint() {
379: return this.tickPaint;
380: }
381:
382:
390: public void setTickPaint(Paint paint) {
391: if (paint == null) {
392: throw new IllegalArgumentException("Null 'paint' argument.");
393: }
394: this.tickPaint = paint;
395: fireChangeEvent();
396: }
397:
398:
405: public String getUnits() {
406: return this.units;
407: }
408:
409:
417: public void setUnits(String units) {
418: this.units = units;
419: fireChangeEvent();
420: }
421:
422:
429: public Paint getNeedlePaint() {
430: return this.needlePaint;
431: }
432:
433:
441: public void setNeedlePaint(Paint paint) {
442: if (paint == null) {
443: throw new IllegalArgumentException("Null 'paint' argument.");
444: }
445: this.needlePaint = paint;
446: fireChangeEvent();
447: }
448:
449:
456: public boolean getTickLabelsVisible() {
457: return this.tickLabelsVisible;
458: }
459:
460:
468: public void setTickLabelsVisible(boolean visible) {
469: if (this.tickLabelsVisible != visible) {
470: this.tickLabelsVisible = visible;
471: fireChangeEvent();
472: }
473: }
474:
475:
482: public Font getTickLabelFont() {
483: return this.tickLabelFont;
484: }
485:
486:
494: public void setTickLabelFont(Font font) {
495: if (font == null) {
496: throw new IllegalArgumentException("Null 'font' argument.");
497: }
498: if (!this.tickLabelFont.equals(font)) {
499: this.tickLabelFont = font;
500: fireChangeEvent();
501: }
502: }
503:
504:
511: public Paint getTickLabelPaint() {
512: return this.tickLabelPaint;
513: }
514:
515:
523: public void setTickLabelPaint(Paint paint) {
524: if (paint == null) {
525: throw new IllegalArgumentException("Null 'paint' argument.");
526: }
527: if (!this.tickLabelPaint.equals(paint)) {
528: this.tickLabelPaint = paint;
529: fireChangeEvent();
530: }
531: }
532:
533:
540: public NumberFormat getTickLabelFormat() {
541: return this.tickLabelFormat;
542: }
543:
544:
552: public void setTickLabelFormat(NumberFormat format) {
553: if (format == null) {
554: throw new IllegalArgumentException("Null 'format' argument.");
555: }
556: this.tickLabelFormat = format;
557: fireChangeEvent();
558: }
559:
560:
567: public Font getValueFont() {
568: return this.valueFont;
569: }
570:
571:
579: public void setValueFont(Font font) {
580: if (font == null) {
581: throw new IllegalArgumentException("Null 'font' argument.");
582: }
583: this.valueFont = font;
584: fireChangeEvent();
585: }
586:
587:
594: public Paint getValuePaint() {
595: return this.valuePaint;
596: }
597:
598:
606: public void setValuePaint(Paint paint) {
607: if (paint == null) {
608: throw new IllegalArgumentException("Null 'paint' argument.");
609: }
610: this.valuePaint = paint;
611: fireChangeEvent();
612: }
613:
614:
621: public Paint getDialBackgroundPaint() {
622: return this.dialBackgroundPaint;
623: }
624:
625:
633: public void setDialBackgroundPaint(Paint paint) {
634: this.dialBackgroundPaint = paint;
635: fireChangeEvent();
636: }
637:
638:
646: public boolean getDrawBorder() {
647: return this.drawBorder;
648: }
649:
650:
659: public void setDrawBorder(boolean draw) {
660:
661: this.drawBorder = draw;
662: fireChangeEvent();
663: }
664:
665:
672: public Paint getDialOutlinePaint() {
673: return this.dialOutlinePaint;
674: }
675:
676:
684: public void setDialOutlinePaint(Paint paint) {
685: this.dialOutlinePaint = paint;
686: fireChangeEvent();
687: }
688:
689:
696: public ValueDataset getDataset() {
697: return this.dataset;
698: }
699:
700:
708: public void setDataset(ValueDataset dataset) {
709:
710:
711:
712: ValueDataset existing = this.dataset;
713: if (existing != null) {
714: existing.removeChangeListener(this);
715: }
716:
717:
718: this.dataset = dataset;
719: if (dataset != null) {
720: setDatasetGroup(dataset.getGroup());
721: dataset.addChangeListener(this);
722: }
723:
724:
725: DatasetChangeEvent event = new DatasetChangeEvent(this, dataset);
726: datasetChanged(event);
727:
728: }
729:
730:
737: public List getIntervals() {
738: return Collections.unmodifiableList(this.intervals);
739: }
740:
741:
750: public void addInterval(MeterInterval interval) {
751: if (interval == null) {
752: throw new IllegalArgumentException("Null 'interval' argument.");
753: }
754: this.intervals.add(interval);
755: fireChangeEvent();
756: }
757:
758:
764: public void clearIntervals() {
765: this.intervals.clear();
766: fireChangeEvent();
767: }
768:
769:
774: public LegendItemCollection getLegendItems() {
775: LegendItemCollection result = new LegendItemCollection();
776: Iterator iterator = this.intervals.iterator();
777: while (iterator.hasNext()) {
778: MeterInterval mi = (MeterInterval) iterator.next();
779: Paint color = mi.getBackgroundPaint();
780: if (color == null) {
781: color = mi.getOutlinePaint();
782: }
783: LegendItem item = new LegendItem(mi.getLabel(), mi.getLabel(),
784: null, null, new Rectangle2D.Double(-4.0, -4.0, 8.0, 8.0),
785: color);
786: item.setDataset(getDataset());
787: result.add(item);
788: }
789: return result;
790: }
791:
792:
802: public void draw(Graphics2D g2, Rectangle2D area, Point2D anchor,
803: PlotState parentState,
804: PlotRenderingInfo info) {
805:
806: if (info != null) {
807: info.setPlotArea(area);
808: }
809:
810:
811: RectangleInsets insets = getInsets();
812: insets.trim(area);
813:
814: area.setRect(area.getX() + 4, area.getY() + 4, area.getWidth() - 8,
815: area.getHeight() - 8);
816:
817:
818: if (this.drawBorder) {
819: drawBackground(g2, area);
820: }
821:
822:
823: double gapHorizontal = (2 * DEFAULT_BORDER_SIZE);
824: double gapVertical = (2 * DEFAULT_BORDER_SIZE);
825: double meterX = area.getX() + gapHorizontal / 2;
826: double meterY = area.getY() + gapVertical / 2;
827: double meterW = area.getWidth() - gapHorizontal;
828: double meterH = area.getHeight() - gapVertical
829: + ((this.meterAngle <= 180) && (this.shape != DialShape.CIRCLE)
830: ? area.getHeight() / 1.25 : 0);
831:
832: double min = Math.min(meterW, meterH) / 2;
833: meterX = (meterX + meterX + meterW) / 2 - min;
834: meterY = (meterY + meterY + meterH) / 2 - min;
835: meterW = 2 * min;
836: meterH = 2 * min;
837:
838: Rectangle2D meterArea = new Rectangle2D.Double(meterX, meterY, meterW,
839: meterH);
840:
841: Rectangle2D.Double originalArea = new Rectangle2D.Double(
842: meterArea.getX() - 4, meterArea.getY() - 4,
843: meterArea.getWidth() + 8, meterArea.getHeight() + 8);
844:
845: double meterMiddleX = meterArea.getCenterX();
846: double meterMiddleY = meterArea.getCenterY();
847:
848:
849: ValueDataset data = getDataset();
850: if (data != null) {
851: double dataMin = this.range.getLowerBound();
852: double dataMax = this.range.getUpperBound();
853:
854: Shape savedClip = g2.getClip();
855: g2.clip(originalArea);
856: Composite originalComposite = g2.getComposite();
857: g2.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER,
858: getForegroundAlpha()));
859:
860: if (this.dialBackgroundPaint != null) {
861: fillArc(g2, originalArea, dataMin, dataMax,
862: this.dialBackgroundPaint, true);
863: }
864: drawTicks(g2, meterArea, dataMin, dataMax);
865: drawArcForInterval(g2, meterArea, new MeterInterval("", this.range,
866: this.dialOutlinePaint, new BasicStroke(1.0f), null));
867:
868: Iterator iterator = this.intervals.iterator();
869: while (iterator.hasNext()) {
870: MeterInterval interval = (MeterInterval) iterator.next();
871: drawArcForInterval(g2, meterArea, interval);
872: }
873:
874: Number n = data.getValue();
875: if (n != null) {
876: double value = n.doubleValue();
877: drawValueLabel(g2, meterArea);
878:
879: if (this.range.contains(value)) {
880: g2.setPaint(this.needlePaint);
881: g2.setStroke(new BasicStroke(2.0f));
882:
883: double radius = (meterArea.getWidth() / 2)
884: + DEFAULT_BORDER_SIZE + 15;
885: double valueAngle = valueToAngle(value);
886: double valueP1 = meterMiddleX
887: + (radius * Math.cos(Math.PI * (valueAngle / 180)));
888: double valueP2 = meterMiddleY
889: - (radius * Math.sin(Math.PI * (valueAngle / 180)));
890:
891: Polygon arrow = new Polygon();
892: if ((valueAngle > 135 && valueAngle < 225)
893: || (valueAngle < 45 && valueAngle > -45)) {
894:
895: double valueP3 = (meterMiddleY
896: - DEFAULT_CIRCLE_SIZE / 4);
897: double valueP4 = (meterMiddleY
898: + DEFAULT_CIRCLE_SIZE / 4);
899: arrow.addPoint((int) meterMiddleX, (int) valueP3);
900: arrow.addPoint((int) meterMiddleX, (int) valueP4);
901:
902: }
903: else {
904: arrow.addPoint((int) (meterMiddleX
905: - DEFAULT_CIRCLE_SIZE / 4), (int) meterMiddleY);
906: arrow.addPoint((int) (meterMiddleX
907: + DEFAULT_CIRCLE_SIZE / 4), (int) meterMiddleY);
908: }
909: arrow.addPoint((int) valueP1, (int) valueP2);
910: g2.fill(arrow);
911:
912: Ellipse2D circle = new Ellipse2D.Double(meterMiddleX
913: - DEFAULT_CIRCLE_SIZE / 2, meterMiddleY
914: - DEFAULT_CIRCLE_SIZE / 2, DEFAULT_CIRCLE_SIZE,
915: DEFAULT_CIRCLE_SIZE);
916: g2.fill(circle);
917: }
918: }
919:
920: g2.setClip(savedClip);
921: g2.setComposite(originalComposite);
922:
923: }
924: if (this.drawBorder) {
925: drawOutline(g2, area);
926: }
927:
928: }
929:
930:
937: protected void drawArcForInterval(Graphics2D g2, Rectangle2D meterArea,
938: MeterInterval interval) {
939:
940: double minValue = interval.getRange().getLowerBound();
941: double maxValue = interval.getRange().getUpperBound();
942: Paint outlinePaint = interval.getOutlinePaint();
943: Stroke outlineStroke = interval.getOutlineStroke();
944: Paint backgroundPaint = interval.getBackgroundPaint();
945:
946: if (backgroundPaint != null) {
947: fillArc(g2, meterArea, minValue, maxValue, backgroundPaint, false);
948: }
949: if (outlinePaint != null) {
950: if (outlineStroke != null) {
951: drawArc(g2, meterArea, minValue, maxValue, outlinePaint,
952: outlineStroke);
953: }
954: drawTick(g2, meterArea, minValue, true);
955: drawTick(g2, meterArea, maxValue, true);
956: }
957: }
958:
959:
969: protected void drawArc(Graphics2D g2, Rectangle2D area, double minValue,
970: double maxValue, Paint paint, Stroke stroke) {
971:
972: double startAngle = valueToAngle(maxValue);
973: double endAngle = valueToAngle(minValue);
974: double extent = endAngle - startAngle;
975:
976: double x = area.getX();
977: double y = area.getY();
978: double w = area.getWidth();
979: double h = area.getHeight();
980: g2.setPaint(paint);
981: g2.setStroke(stroke);
982:
983: if (paint != null && stroke != null) {
984: Arc2D.Double arc = new Arc2D.Double(x, y, w, h, startAngle,
985: extent, Arc2D.OPEN);
986: g2.setPaint(paint);
987: g2.setStroke(stroke);
988: g2.draw(arc);
989: }
990:
991: }
992:
993:
1004: protected void fillArc(Graphics2D g2, Rectangle2D area,
1005: double minValue, double maxValue, Paint paint,
1006: boolean dial) {
1007: if (paint == null) {
1008: throw new IllegalArgumentException("Null 'paint' argument");
1009: }
1010: double startAngle = valueToAngle(maxValue);
1011: double endAngle = valueToAngle(minValue);
1012: double extent = endAngle - startAngle;
1013:
1014: double x = area.getX();
1015: double y = area.getY();
1016: double w = area.getWidth();
1017: double h = area.getHeight();
1018: int joinType = Arc2D.OPEN;
1019: if (this.shape == DialShape.PIE) {
1020: joinType = Arc2D.PIE;
1021: }
1022: else if (this.shape == DialShape.CHORD) {
1023: if (dial && this.meterAngle > 180) {
1024: joinType = Arc2D.CHORD;
1025: }
1026: else {
1027: joinType = Arc2D.PIE;
1028: }
1029: }
1030: else if (this.shape == DialShape.CIRCLE) {
1031: joinType = Arc2D.PIE;
1032: if (dial) {
1033: extent = 360;
1034: }
1035: }
1036: else {
1037: throw new IllegalStateException("DialShape not recognised.");
1038: }
1039:
1040: g2.setPaint(paint);
1041: Arc2D.Double arc = new Arc2D.Double(x, y, w, h, startAngle, extent,
1042: joinType);
1043: g2.fill(arc);
1044: }
1045:
1046:
1053: public double valueToAngle(double value) {
1054: value = value - this.range.getLowerBound();
1055: double baseAngle = 180 + ((this.meterAngle - 180) / 2);
1056: return baseAngle - ((value / this.range.getLength()) * this.meterAngle);
1057: }
1058:
1059:
1067: protected void drawTicks(Graphics2D g2, Rectangle2D meterArea,
1068: double minValue, double maxValue) {
1069: for (double v = minValue; v <= maxValue; v += this.tickSize) {
1070: drawTick(g2, meterArea, v);
1071: }
1072: }
1073:
1074:
1081: protected void drawTick(Graphics2D g2, Rectangle2D meterArea,
1082: double value) {
1083: drawTick(g2, meterArea, value, false);
1084: }
1085:
1086:
1094: protected void drawTick(Graphics2D g2, Rectangle2D meterArea,
1095: double value, boolean label) {
1096:
1097: double valueAngle = valueToAngle(value);
1098:
1099: double meterMiddleX = meterArea.getCenterX();
1100: double meterMiddleY = meterArea.getCenterY();
1101:
1102: g2.setPaint(this.tickPaint);
1103: g2.setStroke(new BasicStroke(2.0f));
1104:
1105: double valueP2X = 0;
1106: double valueP2Y = 0;
1107:
1108: double radius = (meterArea.getWidth() / 2) + DEFAULT_BORDER_SIZE;
1109: double radius1 = radius - 15;
1110:
1111: double valueP1X = meterMiddleX
1112: + (radius * Math.cos(Math.PI * (valueAngle / 180)));
1113: double valueP1Y = meterMiddleY
1114: - (radius * Math.sin(Math.PI * (valueAngle / 180)));
1115:
1116: valueP2X = meterMiddleX
1117: + (radius1 * Math.cos(Math.PI * (valueAngle / 180)));
1118: valueP2Y = meterMiddleY
1119: - (radius1 * Math.sin(Math.PI * (valueAngle / 180)));
1120:
1121: Line2D.Double line = new Line2D.Double(valueP1X, valueP1Y, valueP2X,
1122: valueP2Y);
1123: g2.draw(line);
1124:
1125: if (this.tickLabelsVisible && label) {
1126:
1127: String tickLabel = this.tickLabelFormat.format(value);
1128: g2.setFont(this.tickLabelFont);
1129: g2.setPaint(this.tickLabelPaint);
1130:
1131: FontMetrics fm = g2.getFontMetrics();
1132: Rectangle2D tickLabelBounds
1133: = TextUtilities.getTextBounds(tickLabel, g2, fm);
1134:
1135: double x = valueP2X;
1136: double y = valueP2Y;
1137: if (valueAngle == 90 || valueAngle == 270) {
1138: x = x - tickLabelBounds.getWidth() / 2;
1139: }
1140: else if (valueAngle < 90 || valueAngle > 270) {
1141: x = x - tickLabelBounds.getWidth();
1142: }
1143: if ((valueAngle > 135 && valueAngle < 225)
1144: || valueAngle > 315 || valueAngle < 45) {
1145: y = y - tickLabelBounds.getHeight() / 2;
1146: }
1147: else {
1148: y = y + tickLabelBounds.getHeight() / 2;
1149: }
1150: g2.drawString(tickLabel, (float) x, (float) y);
1151: }
1152: }
1153:
1154:
1160: protected void drawValueLabel(Graphics2D g2, Rectangle2D area) {
1161: g2.setFont(this.valueFont);
1162: g2.setPaint(this.valuePaint);
1163: String valueStr = "No value";
1164: if (this.dataset != null) {
1165: Number n = this.dataset.getValue();
1166: if (n != null) {
1167: valueStr = this.tickLabelFormat.format(n.doubleValue()) + " "
1168: + this.units;
1169: }
1170: }
1171: float x = (float) area.getCenterX();
1172: float y = (float) area.getCenterY() + DEFAULT_CIRCLE_SIZE;
1173: TextUtilities.drawAlignedString(valueStr, g2, x, y,
1174: TextAnchor.TOP_CENTER);
1175: }
1176:
1177:
1182: public String getPlotType() {
1183: return localizationResources.getString("Meter_Plot");
1184: }
1185:
1186:
1193: public void zoom(double percent) {
1194:
1195: }
1196:
1197:
1205: public boolean equals(Object obj) {
1206: if (obj == this) {
1207: return true;
1208: }
1209: if (!(obj instanceof MeterPlot)) {
1210: return false;
1211: }
1212: if (!super.equals(obj)) {
1213: return false;
1214: }
1215: MeterPlot that = (MeterPlot) obj;
1216: if (!ObjectUtilities.equal(this.units, that.units)) {
1217: return false;
1218: }
1219: if (!ObjectUtilities.equal(this.range, that.range)) {
1220: return false;
1221: }
1222: if (!ObjectUtilities.equal(this.intervals, that.intervals)) {
1223: return false;
1224: }
1225: if (!PaintUtilities.equal(this.dialOutlinePaint,
1226: that.dialOutlinePaint)) {
1227: return false;
1228: }
1229: if (this.shape != that.shape) {
1230: return false;
1231: }
1232: if (!PaintUtilities.equal(this.dialBackgroundPaint,
1233: that.dialBackgroundPaint)) {
1234: return false;
1235: }
1236: if (!PaintUtilities.equal(this.needlePaint, that.needlePaint)) {
1237: return false;
1238: }
1239: if (!ObjectUtilities.equal(this.valueFont, that.valueFont)) {
1240: return false;
1241: }
1242: if (!PaintUtilities.equal(this.valuePaint, that.valuePaint)) {
1243: return false;
1244: }
1245: if (!PaintUtilities.equal(this.tickPaint, that.tickPaint)) {
1246: return false;
1247: }
1248: if (this.tickSize != that.tickSize) {
1249: return false;
1250: }
1251: if (this.tickLabelsVisible != that.tickLabelsVisible) {
1252: return false;
1253: }
1254: if (!ObjectUtilities.equal(this.tickLabelFont, that.tickLabelFont)) {
1255: return false;
1256: }
1257: if (!PaintUtilities.equal(this.tickLabelPaint, that.tickLabelPaint)) {
1258: return false;
1259: }
1260: if (!ObjectUtilities.equal(this.tickLabelFormat,
1261: that.tickLabelFormat)) {
1262: return false;
1263: }
1264: if (this.drawBorder != that.drawBorder) {
1265: return false;
1266: }
1267: if (this.meterAngle != that.meterAngle) {
1268: return false;
1269: }
1270: return true;
1271: }
1272:
1273:
1280: private void writeObject(ObjectOutputStream stream) throws IOException {
1281: stream.defaultWriteObject();
1282: SerialUtilities.writePaint(this.dialBackgroundPaint, stream);
1283: SerialUtilities.writePaint(this.dialOutlinePaint, stream);
1284: SerialUtilities.writePaint(this.needlePaint, stream);
1285: SerialUtilities.writePaint(this.valuePaint, stream);
1286: SerialUtilities.writePaint(this.tickPaint, stream);
1287: SerialUtilities.writePaint(this.tickLabelPaint, stream);
1288: }
1289:
1290:
1298: private void readObject(ObjectInputStream stream)
1299: throws IOException, ClassNotFoundException {
1300: stream.defaultReadObject();
1301: this.dialBackgroundPaint = SerialUtilities.readPaint(stream);
1302: this.dialOutlinePaint = SerialUtilities.readPaint(stream);
1303: this.needlePaint = SerialUtilities.readPaint(stream);
1304: this.valuePaint = SerialUtilities.readPaint(stream);
1305: this.tickPaint = SerialUtilities.readPaint(stream);
1306: this.tickLabelPaint = SerialUtilities.readPaint(stream);
1307: if (this.dataset != null) {
1308: this.dataset.addChangeListener(this);
1309: }
1310: }
1311:
1312:
1322: public Object clone() throws CloneNotSupportedException {
1323: MeterPlot clone = (MeterPlot) super.clone();
1324: clone.tickLabelFormat = (NumberFormat) this.tickLabelFormat.clone();
1325:
1326: clone.intervals = new java.util.ArrayList(this.intervals);
1327: if (clone.dataset != null) {
1328: clone.dataset.addChangeListener(clone);
1329: }
1330: return clone;
1331: }
1332:
1333: }