1:
82:
83: package ;
84:
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: import ;
104: import ;
105: import ;
106: import ;
107: import ;
108: import ;
109: import ;
110:
111: import ;
112: import ;
113: import ;
114: import ;
115: import ;
116: import ;
117: import ;
118: import ;
119: import ;
120: import ;
121: import ;
122: import ;
123:
124:
129: public class MeterPlot extends Plot implements Serializable, Cloneable {
130:
131:
132: private static final long serialVersionUID = 2987472457734470962L;
133:
134:
135: static final Paint DEFAULT_DIAL_BACKGROUND_PAINT = Color.black;
136:
137:
138: static final Paint DEFAULT_NEEDLE_PAINT = Color.green;
139:
140:
141: static final Font DEFAULT_VALUE_FONT = new Font("SansSerif", Font.BOLD, 12);
142:
143:
144: static final Paint DEFAULT_VALUE_PAINT = Color.yellow;
145:
146:
147: public static final int DEFAULT_METER_ANGLE = 270;
148:
149:
150: public static final float DEFAULT_BORDER_SIZE = 3f;
151:
152:
153: public static final float DEFAULT_CIRCLE_SIZE = 10f;
154:
155:
156: public static final Font DEFAULT_LABEL_FONT
157: = new Font("SansSerif", Font.BOLD, 10);
158:
159:
160: private ValueDataset dataset;
161:
162:
163: private DialShape shape;
164:
165:
166: private int meterAngle;
167:
168:
169: private Range range;
170:
171:
172: private double tickSize;
173:
174:
175: private Paint tickPaint;
176:
177:
178: private String units;
179:
180:
181: private Font valueFont;
182:
183:
184: private transient Paint valuePaint;
185:
186:
187: private boolean drawBorder;
188:
189:
190: private transient Paint dialOutlinePaint;
191:
192:
193: private transient Paint dialBackgroundPaint;
194:
195:
196: private transient Paint needlePaint;
197:
198:
199: private boolean tickLabelsVisible;
200:
201:
202: private Font tickLabelFont;
203:
204:
205: private Paint tickLabelPaint;
206:
207:
208: private NumberFormat tickLabelFormat;
209:
210:
211: protected static ResourceBundle localizationResources =
212: ResourceBundle.getBundle("org.jfree.chart.plot.LocalizationBundle");
213:
214:
218: private List intervals;
219:
220:
224: public MeterPlot() {
225: this(null);
226: }
227:
228:
233: public MeterPlot(ValueDataset dataset) {
234: super();
235: this.shape = DialShape.CIRCLE;
236: this.meterAngle = DEFAULT_METER_ANGLE;
237: this.range = new Range(0.0, 100.0);
238: this.tickSize = 10.0;
239: this.tickPaint = Color.white;
240: this.units = "Units";
241: this.needlePaint = MeterPlot.DEFAULT_NEEDLE_PAINT;
242: this.tickLabelsVisible = true;
243: this.tickLabelFont = MeterPlot.DEFAULT_LABEL_FONT;
244: this.tickLabelPaint = Color.black;
245: this.tickLabelFormat = NumberFormat.getInstance();
246: this.valueFont = MeterPlot.DEFAULT_VALUE_FONT;
247: this.valuePaint = MeterPlot.DEFAULT_VALUE_PAINT;
248: this.dialBackgroundPaint = MeterPlot.DEFAULT_DIAL_BACKGROUND_PAINT;
249: this.intervals = new java.util.ArrayList();
250: setDataset(dataset);
251: }
252:
253:
258: public DialShape getDialShape() {
259: return this.shape;
260: }
261:
262:
268: public void setDialShape(DialShape shape) {
269: if (shape == null) {
270: throw new IllegalArgumentException("Null 'shape' argument.");
271: }
272: this.shape = shape;
273: notifyListeners(new PlotChangeEvent(this));
274: }
275:
276:
282: public int getMeterAngle() {
283: return this.meterAngle;
284: }
285:
286:
292: public void setMeterAngle(int angle) {
293: if (angle < 1 || angle > 360) {
294: throw new IllegalArgumentException(
295: "Invalid 'angle' (" + angle + ")"
296: );
297: }
298: this.meterAngle = angle;
299: notifyListeners(new PlotChangeEvent(this));
300: }
301:
302:
307: public Range getRange() {
308: return this.range;
309: }
310:
311:
318: public void setRange(Range range) {
319: if (range == null) {
320: throw new IllegalArgumentException("Null 'range' argument.");
321: }
322: if (!(range.getLength() > 0.0)) {
323: throw new IllegalArgumentException(
324: "Range length must be positive."
325: );
326: }
327: this.range = range;
328: notifyListeners(new PlotChangeEvent(this));
329: }
330:
331:
336: public double getTickSize() {
337: return this.tickSize;
338: }
339:
340:
346: public void setTickSize(double size) {
347: if (size <= 0) {
348: throw new IllegalArgumentException("Requires 'size' > 0.");
349: }
350: this.tickSize = size;
351: notifyListeners(new PlotChangeEvent(this));
352: }
353:
354:
360: public Paint getTickPaint() {
361: return this.tickPaint;
362: }
363:
364:
369: public void setTickPaint(Paint paint) {
370: if (paint == null) {
371: throw new IllegalArgumentException("Null 'paint' argument.");
372: }
373: this.tickPaint = paint;
374: notifyListeners(new PlotChangeEvent(this));
375: }
376:
377:
382: public String getUnits() {
383: return this.units;
384: }
385:
386:
392: public void setUnits(String units) {
393: this.units = units;
394: notifyListeners(new PlotChangeEvent(this));
395: }
396:
397:
402: public Paint getNeedlePaint() {
403: return this.needlePaint;
404: }
405:
406:
412: public void setNeedlePaint(Paint paint) {
413: if (paint == null) {
414: throw new IllegalArgumentException("Null 'paint' argument.");
415: }
416: this.needlePaint = paint;
417: notifyListeners(new PlotChangeEvent(this));
418: }
419:
420:
425: public boolean getTickLabelsVisible() {
426: return this.tickLabelsVisible;
427: }
428:
429:
435: public void setTickLabelsVisible(boolean visible) {
436: if (this.tickLabelsVisible != visible) {
437: this.tickLabelsVisible = visible;
438: notifyListeners(new PlotChangeEvent(this));
439: }
440: }
441:
442:
447: public Font getTickLabelFont() {
448: return this.tickLabelFont;
449: }
450:
451:
457: public void setTickLabelFont(Font font) {
458: if (font == null) {
459: throw new IllegalArgumentException("Null 'font' argument.");
460: }
461: if (!this.tickLabelFont.equals(font)) {
462: this.tickLabelFont = font;
463: notifyListeners(new PlotChangeEvent(this));
464: }
465: }
466:
467:
472: public Paint getTickLabelPaint() {
473: return this.tickLabelPaint;
474: }
475:
476:
482: public void setTickLabelPaint(Paint paint) {
483: if (paint == null) {
484: throw new IllegalArgumentException("Null 'paint' argument.");
485: }
486: if (!this.tickLabelPaint.equals(paint)) {
487: this.tickLabelPaint = paint;
488: notifyListeners(new PlotChangeEvent(this));
489: }
490: }
491:
492:
497: public NumberFormat getTickLabelFormat() {
498: return this.tickLabelFormat;
499: }
500:
501:
507: public void setTickLabelFormat(NumberFormat format) {
508: if (format == null) {
509: throw new IllegalArgumentException("Null 'format' argument.");
510: }
511: this.tickLabelFormat = format;
512: notifyListeners(new PlotChangeEvent(this));
513: }
514:
515:
520: public Font getValueFont() {
521: return this.valueFont;
522: }
523:
524:
530: public void setValueFont(Font font) {
531: if (font == null) {
532: throw new IllegalArgumentException("Null 'font' argument.");
533: }
534: this.valueFont = font;
535: notifyListeners(new PlotChangeEvent(this));
536: }
537:
538:
543: public Paint getValuePaint() {
544: return this.valuePaint;
545: }
546:
547:
553: public void setValuePaint(Paint paint) {
554: if (paint == null) {
555: throw new IllegalArgumentException("Null 'paint' argument.");
556: }
557: this.valuePaint = paint;
558: notifyListeners(new PlotChangeEvent(this));
559: }
560:
561:
566: public Paint getDialBackgroundPaint() {
567: return this.dialBackgroundPaint;
568: }
569:
570:
576: public void setDialBackgroundPaint(Paint paint) {
577: this.dialBackgroundPaint = paint;
578: notifyListeners(new PlotChangeEvent(this));
579: }
580:
581:
587: public boolean getDrawBorder() {
588: return this.drawBorder;
589: }
590:
591:
598: public void setDrawBorder(boolean draw) {
599:
600: this.drawBorder = draw;
601: notifyListeners(new PlotChangeEvent(this));
602: }
603:
604:
609: public Paint getDialOutlinePaint() {
610: return this.dialOutlinePaint;
611: }
612:
613:
619: public void setDialOutlinePaint(Paint paint) {
620: this.dialOutlinePaint = paint;
621: notifyListeners(new PlotChangeEvent(this));
622: }
623:
624:
629: public ValueDataset getDataset() {
630: return this.dataset;
631: }
632:
633:
639: public void setDataset(ValueDataset dataset) {
640:
641:
642:
643: ValueDataset existing = this.dataset;
644: if (existing != null) {
645: existing.removeChangeListener(this);
646: }
647:
648:
649: this.dataset = dataset;
650: if (dataset != null) {
651: setDatasetGroup(dataset.getGroup());
652: dataset.addChangeListener(this);
653: }
654:
655:
656: DatasetChangeEvent event = new DatasetChangeEvent(this, dataset);
657: datasetChanged(event);
658:
659: }
660:
661:
666: public List getIntervals() {
667: return Collections.unmodifiableList(this.intervals);
668: }
669:
670:
676: public void addInterval(MeterInterval interval) {
677: if (interval == null) {
678: throw new IllegalArgumentException("Null 'interval' argument.");
679: }
680: this.intervals.add(interval);
681: notifyListeners(new PlotChangeEvent(this));
682: }
683:
684:
688: public void clearIntervals() {
689: this.intervals.clear();
690: notifyListeners(new PlotChangeEvent(this));
691: }
692:
693:
698: public LegendItemCollection getLegendItems() {
699: LegendItemCollection result = new LegendItemCollection();
700: Iterator iterator = this.intervals.iterator();
701: while (iterator.hasNext()) {
702: MeterInterval mi = (MeterInterval) iterator.next();
703: Paint color = mi.getBackgroundPaint();
704: if (color == null) {
705: color = mi.getOutlinePaint();
706: }
707: LegendItem item = new LegendItem(mi.getLabel(), mi.getLabel(),
708: null, null, new Rectangle2D.Double(-4.0, -4.0, 8.0, 8.0),
709: color);
710: result.add(item);
711: }
712: return result;
713: }
714:
715:
725: public void draw(Graphics2D g2, Rectangle2D area, Point2D anchor,
726: PlotState parentState,
727: PlotRenderingInfo info) {
728:
729: if (info != null) {
730: info.setPlotArea(area);
731: }
732:
733:
734: RectangleInsets insets = getInsets();
735: insets.trim(area);
736:
737: area.setRect(
738: area.getX() + 4, area.getY() + 4,
739: area.getWidth() - 8, area.getHeight() - 8
740: );
741:
742:
743: if (this.drawBorder) {
744: drawBackground(g2, area);
745: }
746:
747:
748: double gapHorizontal = (2 * DEFAULT_BORDER_SIZE);
749: double gapVertical = (2 * DEFAULT_BORDER_SIZE);
750: double meterX = area.getX() + gapHorizontal / 2;
751: double meterY = area.getY() + gapVertical / 2;
752: double meterW = area.getWidth() - gapHorizontal;
753: double meterH = area.getHeight() - gapVertical
754: + ((this.meterAngle <= 180) && (this.shape != DialShape.CIRCLE)
755: ? area.getHeight() / 1.25 : 0);
756:
757: double min = Math.min(meterW, meterH) / 2;
758: meterX = (meterX + meterX + meterW) / 2 - min;
759: meterY = (meterY + meterY + meterH) / 2 - min;
760: meterW = 2 * min;
761: meterH = 2 * min;
762:
763: Rectangle2D meterArea = new Rectangle2D.Double(
764: meterX, meterY, meterW, meterH
765: );
766:
767: Rectangle2D.Double originalArea = new Rectangle2D.Double(
768: meterArea.getX() - 4, meterArea.getY() - 4,
769: meterArea.getWidth() + 8, meterArea.getHeight() + 8
770: );
771:
772: double meterMiddleX = meterArea.getCenterX();
773: double meterMiddleY = meterArea.getCenterY();
774:
775:
776: ValueDataset data = getDataset();
777: if (data != null) {
778: double dataMin = this.range.getLowerBound();
779: double dataMax = this.range.getUpperBound();
780:
781: Shape savedClip = g2.getClip();
782: g2.clip(originalArea);
783: Composite originalComposite = g2.getComposite();
784: g2.setComposite(AlphaComposite.getInstance(
785: AlphaComposite.SRC_OVER, getForegroundAlpha())
786: );
787:
788: if (this.dialBackgroundPaint != null) {
789: fillArc(
790: g2, originalArea, dataMin, dataMax,
791: this.dialBackgroundPaint, true
792: );
793: }
794: drawTicks(g2, meterArea, dataMin, dataMax);
795: drawArcForInterval(
796: g2, meterArea,
797: new MeterInterval(
798: "", this.range, this.dialOutlinePaint,
799: new BasicStroke(1.0f), null
800: )
801: );
802:
803: Iterator iterator = this.intervals.iterator();
804: while (iterator.hasNext()) {
805: MeterInterval interval = (MeterInterval) iterator.next();
806: drawArcForInterval(g2, meterArea, interval);
807: }
808:
809: Number n = data.getValue();
810: if (n != null) {
811: double value = n.doubleValue();
812: drawValueLabel(g2, meterArea);
813:
814: if (this.range.contains(value)) {
815: g2.setPaint(this.needlePaint);
816: g2.setStroke(new BasicStroke(2.0f));
817:
818: double radius = (meterArea.getWidth() / 2)
819: + DEFAULT_BORDER_SIZE + 15;
820: double valueAngle = valueToAngle(value);
821: double valueP1 = meterMiddleX
822: + (radius * Math.cos(Math.PI * (valueAngle / 180)));
823: double valueP2 = meterMiddleY
824: - (radius * Math.sin(Math.PI * (valueAngle / 180)));
825:
826: Polygon arrow = new Polygon();
827: if ((valueAngle > 135 && valueAngle < 225)
828: || (valueAngle < 45 && valueAngle > -45)) {
829:
830: double valueP3 = (meterMiddleY
831: - DEFAULT_CIRCLE_SIZE / 4);
832: double valueP4 = (meterMiddleY
833: + DEFAULT_CIRCLE_SIZE / 4);
834: arrow.addPoint((int) meterMiddleX, (int) valueP3);
835: arrow.addPoint((int) meterMiddleX, (int) valueP4);
836:
837: }
838: else {
839: arrow.addPoint(
840: (int) (meterMiddleX - DEFAULT_CIRCLE_SIZE / 4),
841: (int) meterMiddleY
842: );
843: arrow.addPoint(
844: (int) (meterMiddleX + DEFAULT_CIRCLE_SIZE / 4),
845: (int) meterMiddleY
846: );
847: }
848: arrow.addPoint((int) valueP1, (int) valueP2);
849: g2.fill(arrow);
850:
851: Ellipse2D circle = new Ellipse2D.Double(
852: meterMiddleX - DEFAULT_CIRCLE_SIZE / 2,
853: meterMiddleY - DEFAULT_CIRCLE_SIZE / 2,
854: DEFAULT_CIRCLE_SIZE, DEFAULT_CIRCLE_SIZE
855: );
856: g2.fill(circle);
857: }
858: }
859:
860:
861: g2.clip(savedClip);
862: g2.setComposite(originalComposite);
863:
864: }
865: if (this.drawBorder) {
866: drawOutline(g2, area);
867: }
868:
869: }
870:
871:
878: protected void drawArcForInterval(Graphics2D g2, Rectangle2D meterArea,
879: MeterInterval interval) {
880:
881: double minValue = interval.getRange().getLowerBound();
882: double maxValue = interval.getRange().getUpperBound();
883: Paint outlinePaint = interval.getOutlinePaint();
884: Stroke outlineStroke = interval.getOutlineStroke();
885: Paint backgroundPaint = interval.getBackgroundPaint();
886:
887: if (backgroundPaint != null) {
888: fillArc(g2, meterArea, minValue, maxValue, backgroundPaint, false);
889: }
890: if (outlinePaint != null) {
891: if (outlineStroke != null) {
892: drawArc(
893: g2, meterArea, minValue, maxValue,
894: outlinePaint, outlineStroke
895: );
896: }
897: drawTick(g2, meterArea, minValue, true);
898: drawTick(g2, meterArea, maxValue, true);
899: }
900: }
901:
902:
912: protected void drawArc(Graphics2D g2, Rectangle2D area, double minValue,
913: double maxValue, Paint paint, Stroke stroke) {
914:
915: double startAngle = valueToAngle(maxValue);
916: double endAngle = valueToAngle(minValue);
917: double extent = endAngle - startAngle;
918:
919: double x = area.getX();
920: double y = area.getY();
921: double w = area.getWidth();
922: double h = area.getHeight();
923: g2.setPaint(paint);
924: g2.setStroke(stroke);
925:
926: if (paint != null && stroke != null) {
927: Arc2D.Double arc = new Arc2D.Double(
928: x, y, w, h, startAngle, extent, Arc2D.OPEN
929: );
930: g2.setPaint(paint);
931: g2.setStroke(stroke);
932: g2.draw(arc);
933: }
934:
935: }
936:
937:
948: protected void fillArc(Graphics2D g2, Rectangle2D area,
949: double minValue, double maxValue, Paint paint,
950: boolean dial) {
951: if (paint == null) {
952: throw new IllegalArgumentException("Null 'paint' argument");
953: }
954: double startAngle = valueToAngle(maxValue);
955: double endAngle = valueToAngle(minValue);
956: double extent = endAngle - startAngle;
957:
958: double x = area.getX();
959: double y = area.getY();
960: double w = area.getWidth();
961: double h = area.getHeight();
962: int joinType = Arc2D.OPEN;
963: if (this.shape == DialShape.PIE) {
964: joinType = Arc2D.PIE;
965: }
966: else if (this.shape == DialShape.CHORD) {
967: if (dial && this.meterAngle > 180) {
968: joinType = Arc2D.CHORD;
969: }
970: else {
971: joinType = Arc2D.PIE;
972: }
973: }
974: else if (this.shape == DialShape.CIRCLE) {
975: joinType = Arc2D.PIE;
976: if (dial) {
977: extent = 360;
978: }
979: }
980: else {
981: throw new IllegalStateException("DialShape not recognised.");
982: }
983:
984: g2.setPaint(paint);
985: Arc2D.Double arc = new Arc2D.Double(
986: x, y, w, h, startAngle, extent, joinType
987: );
988: g2.fill(arc);
989: }
990:
991:
998: public double valueToAngle(double value) {
999: value = value - this.range.getLowerBound();
1000: double baseAngle = 180 + ((this.meterAngle - 180) / 2);
1001: return baseAngle - ((value / this.range.getLength()) * this.meterAngle);
1002: }
1003:
1004:
1012: protected void drawTicks(Graphics2D g2, Rectangle2D meterArea,
1013: double minValue, double maxValue) {
1014: for (double v = minValue; v <= maxValue; v += tickSize) {
1015: drawTick(g2, meterArea, v);
1016: }
1017: }
1018:
1019:
1026: protected void drawTick(Graphics2D g2, Rectangle2D meterArea,
1027: double value) {
1028: drawTick(g2, meterArea, value, false);
1029: }
1030:
1031:
1039: protected void drawTick(Graphics2D g2, Rectangle2D meterArea,
1040: double value, boolean label) {
1041:
1042: double valueAngle = valueToAngle(value);
1043:
1044: double meterMiddleX = meterArea.getCenterX();
1045: double meterMiddleY = meterArea.getCenterY();
1046:
1047: g2.setPaint(this.tickPaint);
1048: g2.setStroke(new BasicStroke(2.0f));
1049:
1050: double valueP2X = 0;
1051: double valueP2Y = 0;
1052:
1053: double radius = (meterArea.getWidth() / 2) + DEFAULT_BORDER_SIZE;
1054: double radius1 = radius - 15;
1055:
1056: double valueP1X = meterMiddleX
1057: + (radius * Math.cos(Math.PI * (valueAngle / 180)));
1058: double valueP1Y = meterMiddleY
1059: - (radius * Math.sin(Math.PI * (valueAngle / 180)));
1060:
1061: valueP2X = meterMiddleX
1062: + (radius1 * Math.cos(Math.PI * (valueAngle / 180)));
1063: valueP2Y = meterMiddleY
1064: - (radius1 * Math.sin(Math.PI * (valueAngle / 180)));
1065:
1066: Line2D.Double line = new Line2D.Double(valueP1X, valueP1Y, valueP2X,
1067: valueP2Y);
1068: g2.draw(line);
1069:
1070: if (this.tickLabelsVisible && label) {
1071:
1072: String tickLabel = this.tickLabelFormat.format(value);
1073: g2.setFont(this.tickLabelFont);
1074: g2.setPaint(this.tickLabelPaint);
1075:
1076: FontMetrics fm = g2.getFontMetrics();
1077: Rectangle2D tickLabelBounds
1078: = TextUtilities.getTextBounds(tickLabel, g2, fm);
1079:
1080: double x = valueP2X;
1081: double y = valueP2Y;
1082: if (valueAngle == 90 || valueAngle == 270) {
1083: x = x - tickLabelBounds.getWidth() / 2;
1084: }
1085: else if (valueAngle < 90 || valueAngle > 270) {
1086: x = x - tickLabelBounds.getWidth();
1087: }
1088: if ((valueAngle > 135 && valueAngle < 225)
1089: || valueAngle > 315 || valueAngle < 45) {
1090: y = y - tickLabelBounds.getHeight() / 2;
1091: }
1092: else {
1093: y = y + tickLabelBounds.getHeight() / 2;
1094: }
1095: g2.drawString(tickLabel, (float) x, (float) y);
1096: }
1097: }
1098:
1099:
1105: protected void drawValueLabel(Graphics2D g2, Rectangle2D area) {
1106: g2.setFont(this.valueFont);
1107: g2.setPaint(this.valuePaint);
1108: String valueStr = "No value";
1109: if (dataset != null) {
1110: Number n = dataset.getValue();
1111: if (n != null) {
1112: valueStr = this.tickLabelFormat.format(n.doubleValue()) + " "
1113: + this.units;
1114: }
1115: }
1116: float x = (float) area.getCenterX();
1117: float y = (float) area.getCenterY() + DEFAULT_CIRCLE_SIZE;
1118: TextUtilities.drawAlignedString(valueStr, g2, x, y,
1119: TextAnchor.TOP_CENTER);
1120: }
1121:
1122:
1127: public String getPlotType() {
1128: return localizationResources.getString("Meter_Plot");
1129: }
1130:
1131:
1138: public void zoom(double percent) {
1139:
1140: }
1141:
1142:
1150: public boolean equals(Object obj) {
1151: if (obj == this) {
1152: return true;
1153: }
1154: if (!(obj instanceof MeterPlot)) {
1155: return false;
1156: }
1157: if (!super.equals(obj)) {
1158: return false;
1159: }
1160: MeterPlot that = (MeterPlot) obj;
1161: if (!ObjectUtilities.equal(this.units, that.units)) {
1162: return false;
1163: }
1164: if (!ObjectUtilities.equal(this.range, that.range)) {
1165: return false;
1166: }
1167: if (!ObjectUtilities.equal(this.intervals, that.intervals)) {
1168: return false;
1169: }
1170: if (!PaintUtilities.equal(this.dialOutlinePaint,
1171: that.dialOutlinePaint)) {
1172: return false;
1173: }
1174: if (this.shape != that.shape) {
1175: return false;
1176: }
1177: if (!PaintUtilities.equal(this.dialBackgroundPaint,
1178: that.dialBackgroundPaint)) {
1179: return false;
1180: }
1181: if (!PaintUtilities.equal(this.needlePaint, that.needlePaint)) {
1182: return false;
1183: }
1184: if (!ObjectUtilities.equal(this.valueFont, that.valueFont)) {
1185: return false;
1186: }
1187: if (!PaintUtilities.equal(this.valuePaint, that.valuePaint)) {
1188: return false;
1189: }
1190: if (!PaintUtilities.equal(this.tickPaint, that.tickPaint)) {
1191: return false;
1192: }
1193: if (this.tickSize != that.tickSize) {
1194: return false;
1195: }
1196: if (this.tickLabelsVisible != that.tickLabelsVisible) {
1197: return false;
1198: }
1199: if (!ObjectUtilities.equal(this.tickLabelFont, that.tickLabelFont)) {
1200: return false;
1201: }
1202: if (!PaintUtilities.equal(this.tickLabelPaint, that.tickLabelPaint)) {
1203: return false;
1204: }
1205: if (!ObjectUtilities.equal(this.tickLabelFormat,
1206: that.tickLabelFormat)) {
1207: return false;
1208: }
1209: if (this.drawBorder != that.drawBorder) {
1210: return false;
1211: }
1212: if (this.meterAngle != that.meterAngle) {
1213: return false;
1214: }
1215: return true;
1216: }
1217:
1218:
1225: private void writeObject(ObjectOutputStream stream) throws IOException {
1226: stream.defaultWriteObject();
1227: SerialUtilities.writePaint(this.dialBackgroundPaint, stream);
1228: SerialUtilities.writePaint(this.needlePaint, stream);
1229: SerialUtilities.writePaint(this.valuePaint, stream);
1230: }
1231:
1232:
1240: private void readObject(ObjectInputStream stream)
1241: throws IOException, ClassNotFoundException {
1242: stream.defaultReadObject();
1243: this.dialBackgroundPaint = SerialUtilities.readPaint(stream);
1244: this.needlePaint = SerialUtilities.readPaint(stream);
1245: this.valuePaint = SerialUtilities.readPaint(stream);
1246: if (this.dataset != null) {
1247: this.dataset.addChangeListener(this);
1248: }
1249: }
1250:
1251:
1261: public Object clone() throws CloneNotSupportedException {
1262: MeterPlot clone = (MeterPlot) super.clone();
1263: clone.tickLabelFormat = (NumberFormat) this.tickLabelFormat.clone();
1264:
1265: clone.intervals = new java.util.ArrayList(this.intervals);
1266: if (clone.dataset != null) {
1267: clone.dataset.addChangeListener(clone);
1268: }
1269: return clone;
1270: }
1271:
1272: }