1:
61:
62: package ;
63:
64: import ;
65: import ;
66: import ;
67: import ;
68: import ;
69: import ;
70: import ;
71: import ;
72: import ;
73: import ;
74: import ;
75:
76: import ;
77: import ;
78: import ;
79: import ;
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:
93:
96: public class XYLineAndShapeRenderer extends AbstractXYItemRenderer
97: implements XYItemRenderer,
98: Cloneable,
99: PublicCloneable,
100: Serializable {
101:
102:
103: private static final long serialVersionUID = -7435246895986425885L;
104:
105:
106: private Boolean linesVisible;
107:
108:
112: private BooleanList seriesLinesVisible;
113:
114:
115: private boolean baseLinesVisible;
116:
117:
118: private transient Shape legendLine;
119:
120:
123: private Boolean shapesVisible;
124:
125:
129: private BooleanList seriesShapesVisible;
130:
131:
132: private boolean baseShapesVisible;
133:
134:
135: private Boolean shapesFilled;
136:
137:
141: private BooleanList seriesShapesFilled;
142:
143:
144: private boolean baseShapesFilled;
145:
146:
147: private boolean drawOutlines;
148:
149:
153: private boolean useFillPaint;
154:
155:
159: private boolean useOutlinePaint;
160:
161:
165: private boolean drawSeriesLineAsPath;
166:
167:
170: public XYLineAndShapeRenderer() {
171: this(true, true);
172: }
173:
174:
180: public XYLineAndShapeRenderer(boolean lines, boolean shapes) {
181: this.linesVisible = null;
182: this.seriesLinesVisible = new BooleanList();
183: this.baseLinesVisible = lines;
184: this.legendLine = new Line2D.Double(-7.0, 0.0, 7.0, 0.0);
185:
186: this.shapesVisible = null;
187: this.seriesShapesVisible = new BooleanList();
188: this.baseShapesVisible = shapes;
189:
190: this.shapesFilled = null;
191: this.useFillPaint = false;
192: this.seriesShapesFilled = new BooleanList();
193: this.baseShapesFilled = true;
194:
195: this.drawOutlines = true;
196: this.useOutlinePaint = false;
197:
198:
199: this.drawSeriesLineAsPath = false;
200: }
201:
202:
210: public boolean getDrawSeriesLineAsPath() {
211: return this.drawSeriesLineAsPath;
212: }
213:
214:
222: public void setDrawSeriesLineAsPath(boolean flag) {
223: if (this.drawSeriesLineAsPath != flag) {
224: this.drawSeriesLineAsPath = flag;
225: notifyListeners(new RendererChangeEvent(this));
226: }
227: }
228:
229:
236: public int getPassCount() {
237: return 2;
238: }
239:
240:
241:
242:
251: public boolean getItemLineVisible(int series, int item) {
252: Boolean flag = this.linesVisible;
253: if (flag == null) {
254: flag = getSeriesLinesVisible(series);
255: }
256: if (flag != null) {
257: return flag.booleanValue();
258: }
259: else {
260: return this.baseLinesVisible;
261: }
262: }
263:
264:
271: public Boolean getLinesVisible() {
272: return this.linesVisible;
273: }
274:
275:
283: public void setLinesVisible(Boolean visible) {
284: this.linesVisible = visible;
285: notifyListeners(new RendererChangeEvent(this));
286: }
287:
288:
295: public void setLinesVisible(boolean visible) {
296: setLinesVisible(BooleanUtilities.valueOf(visible));
297: }
298:
299:
307: public Boolean getSeriesLinesVisible(int series) {
308: return this.seriesLinesVisible.getBoolean(series);
309: }
310:
311:
317: public void setSeriesLinesVisible(int series, Boolean flag) {
318: this.seriesLinesVisible.setBoolean(series, flag);
319: notifyListeners(new RendererChangeEvent(this));
320: }
321:
322:
328: public void setSeriesLinesVisible(int series, boolean visible) {
329: setSeriesLinesVisible(series, BooleanUtilities.valueOf(visible));
330: }
331:
332:
337: public boolean getBaseLinesVisible() {
338: return this.baseLinesVisible;
339: }
340:
341:
346: public void setBaseLinesVisible(boolean flag) {
347: this.baseLinesVisible = flag;
348: notifyListeners(new RendererChangeEvent(this));
349: }
350:
351:
356: public Shape getLegendLine() {
357: return this.legendLine;
358: }
359:
360:
366: public void setLegendLine(Shape line) {
367: if (line == null) {
368: throw new IllegalArgumentException("Null 'line' argument.");
369: }
370: this.legendLine = line;
371: notifyListeners(new RendererChangeEvent(this));
372: }
373:
374:
375:
376:
389: public boolean getItemShapeVisible(int series, int item) {
390: Boolean flag = this.shapesVisible;
391: if (flag == null) {
392: flag = getSeriesShapesVisible(series);
393: }
394: if (flag != null) {
395: return flag.booleanValue();
396: }
397: else {
398: return this.baseShapesVisible;
399: }
400: }
401:
402:
408: public Boolean getShapesVisible() {
409: return this.shapesVisible;
410: }
411:
412:
418: public void setShapesVisible(Boolean visible) {
419: this.shapesVisible = visible;
420: notifyListeners(new RendererChangeEvent(this));
421: }
422:
423:
429: public void setShapesVisible(boolean visible) {
430: setShapesVisible(BooleanUtilities.valueOf(visible));
431: }
432:
433:
441: public Boolean getSeriesShapesVisible(int series) {
442: return this.seriesShapesVisible.getBoolean(series);
443: }
444:
445:
452: public void setSeriesShapesVisible(int series, boolean visible) {
453: setSeriesShapesVisible(series, BooleanUtilities.valueOf(visible));
454: }
455:
456:
463: public void setSeriesShapesVisible(int series, Boolean flag) {
464: this.seriesShapesVisible.setBoolean(series, flag);
465: notifyListeners(new RendererChangeEvent(this));
466: }
467:
468:
473: public boolean getBaseShapesVisible() {
474: return this.baseShapesVisible;
475: }
476:
477:
482: public void setBaseShapesVisible(boolean flag) {
483: this.baseShapesVisible = flag;
484: notifyListeners(new RendererChangeEvent(this));
485: }
486:
487:
488:
489:
502: public boolean getItemShapeFilled(int series, int item) {
503: Boolean flag = this.shapesFilled;
504: if (flag == null) {
505: flag = getSeriesShapesFilled(series);
506: }
507: if (flag != null) {
508: return flag.booleanValue();
509: }
510: else {
511: return this.baseShapesFilled;
512: }
513: }
514:
515:
521: public void setShapesFilled(boolean filled) {
522: setShapesFilled(BooleanUtilities.valueOf(filled));
523: }
524:
525:
531: public void setShapesFilled(Boolean filled) {
532: this.shapesFilled = filled;
533: notifyListeners(new RendererChangeEvent(this));
534: }
535:
536:
544: public Boolean getSeriesShapesFilled(int series) {
545: return this.seriesShapesFilled.getBoolean(series);
546: }
547:
548:
554: public void setSeriesShapesFilled(int series, boolean flag) {
555: setSeriesShapesFilled(series, BooleanUtilities.valueOf(flag));
556: }
557:
558:
564: public void setSeriesShapesFilled(int series, Boolean flag) {
565: this.seriesShapesFilled.setBoolean(series, flag);
566: notifyListeners(new RendererChangeEvent(this));
567: }
568:
569:
574: public boolean getBaseShapesFilled() {
575: return this.baseShapesFilled;
576: }
577:
578:
583: public void setBaseShapesFilled(boolean flag) {
584: this.baseShapesFilled = flag;
585: notifyListeners(new RendererChangeEvent(this));
586: }
587:
588:
594: public boolean getDrawOutlines() {
595: return this.drawOutlines;
596: }
597:
598:
608: public void setDrawOutlines(boolean flag) {
609: this.drawOutlines = flag;
610: notifyListeners(new RendererChangeEvent(this));
611: }
612:
613:
620: public boolean getUseFillPaint() {
621: return this.useFillPaint;
622: }
623:
624:
631: public void setUseFillPaint(boolean flag) {
632: this.useFillPaint = flag;
633: notifyListeners(new RendererChangeEvent(this));
634: }
635:
636:
643: public boolean getUseOutlinePaint() {
644: return this.useOutlinePaint;
645: }
646:
647:
654: public void setUseOutlinePaint(boolean flag) {
655: this.useOutlinePaint = flag;
656: notifyListeners(new RendererChangeEvent(this));
657: }
658:
659:
664: public static class State extends XYItemRendererState {
665:
666:
667: public GeneralPath seriesPath;
668:
669:
673: private boolean lastPointGood;
674:
675:
680: public State(PlotRenderingInfo info) {
681: super(info);
682: }
683:
684:
690: public boolean isLastPointGood() {
691: return this.lastPointGood;
692: }
693:
694:
700: public void setLastPointGood(boolean good) {
701: this.lastPointGood = good;
702: }
703: }
704:
705:
721: public XYItemRendererState initialise(Graphics2D g2,
722: Rectangle2D dataArea,
723: XYPlot plot,
724: XYDataset data,
725: PlotRenderingInfo info) {
726:
727: State state = new State(info);
728: state.seriesPath = new GeneralPath();
729: return state;
730:
731: }
732:
733:
751: public void drawItem(Graphics2D g2,
752: XYItemRendererState state,
753: Rectangle2D dataArea,
754: PlotRenderingInfo info,
755: XYPlot plot,
756: ValueAxis domainAxis,
757: ValueAxis rangeAxis,
758: XYDataset dataset,
759: int series,
760: int item,
761: CrosshairState crosshairState,
762: int pass) {
763:
764:
765: if (!getItemVisible(series, item)) {
766: return;
767: }
768:
769:
770: if (isLinePass(pass)) {
771: if (item == 0) {
772: if (this.drawSeriesLineAsPath) {
773: State s = (State) state;
774: s.seriesPath.reset();
775: s.lastPointGood = false;
776: }
777: }
778:
779: if (getItemLineVisible(series, item)) {
780: if (this.drawSeriesLineAsPath) {
781: drawPrimaryLineAsPath(state, g2, plot, dataset, pass,
782: series, item, domainAxis, rangeAxis, dataArea);
783: }
784: else {
785: drawPrimaryLine(state, g2, plot, dataset, pass, series,
786: item, domainAxis, rangeAxis, dataArea);
787: }
788: }
789: }
790:
791: else if (isItemPass(pass)) {
792:
793:
794: EntityCollection entities = null;
795: if (info != null) {
796: entities = info.getOwner().getEntityCollection();
797: }
798:
799: drawSecondaryPass(g2, plot, dataset, pass, series, item,
800: domainAxis, dataArea, rangeAxis, crosshairState, entities);
801: }
802: }
803:
804:
812: protected boolean isLinePass(int pass) {
813: return pass == 0;
814: }
815:
816:
824: protected boolean isItemPass(int pass) {
825: return pass == 1;
826: }
827:
828:
844: protected void drawPrimaryLine(XYItemRendererState state,
845: Graphics2D g2,
846: XYPlot plot,
847: XYDataset dataset,
848: int pass,
849: int series,
850: int item,
851: ValueAxis domainAxis,
852: ValueAxis rangeAxis,
853: Rectangle2D dataArea) {
854: if (item == 0) {
855: return;
856: }
857:
858:
859: double x1 = dataset.getXValue(series, item);
860: double y1 = dataset.getYValue(series, item);
861: if (Double.isNaN(y1) || Double.isNaN(x1)) {
862: return;
863: }
864:
865: double x0 = dataset.getXValue(series, item - 1);
866: double y0 = dataset.getYValue(series, item - 1);
867: if (Double.isNaN(y0) || Double.isNaN(x0)) {
868: return;
869: }
870:
871: RectangleEdge xAxisLocation = plot.getDomainAxisEdge();
872: RectangleEdge yAxisLocation = plot.getRangeAxisEdge();
873:
874: double transX0 = domainAxis.valueToJava2D(x0, dataArea, xAxisLocation);
875: double transY0 = rangeAxis.valueToJava2D(y0, dataArea, yAxisLocation);
876:
877: double transX1 = domainAxis.valueToJava2D(x1, dataArea, xAxisLocation);
878: double transY1 = rangeAxis.valueToJava2D(y1, dataArea, yAxisLocation);
879:
880:
881: if (Double.isNaN(transX0) || Double.isNaN(transY0)
882: || Double.isNaN(transX1) || Double.isNaN(transY1)) {
883: return;
884: }
885:
886: PlotOrientation orientation = plot.getOrientation();
887: if (orientation == PlotOrientation.HORIZONTAL) {
888: state.workingLine.setLine(transY0, transX0, transY1, transX1);
889: }
890: else if (orientation == PlotOrientation.VERTICAL) {
891: state.workingLine.setLine(transX0, transY0, transX1, transY1);
892: }
893:
894: if (state.workingLine.intersects(dataArea)) {
895: drawFirstPassShape(g2, pass, series, item, state.workingLine);
896: }
897: }
898:
899:
908: protected void drawFirstPassShape(Graphics2D g2, int pass, int series,
909: int item, Shape shape) {
910: g2.setStroke(getItemStroke(series, item));
911: g2.setPaint(getItemPaint(series, item));
912: g2.draw(shape);
913: }
914:
915:
916:
934: protected void drawPrimaryLineAsPath(XYItemRendererState state,
935: Graphics2D g2, XYPlot plot,
936: XYDataset dataset,
937: int pass,
938: int series,
939: int item,
940: ValueAxis domainAxis,
941: ValueAxis rangeAxis,
942: Rectangle2D dataArea) {
943:
944:
945: RectangleEdge xAxisLocation = plot.getDomainAxisEdge();
946: RectangleEdge yAxisLocation = plot.getRangeAxisEdge();
947:
948:
949: double x1 = dataset.getXValue(series, item);
950: double y1 = dataset.getYValue(series, item);
951: double transX1 = domainAxis.valueToJava2D(x1, dataArea, xAxisLocation);
952: double transY1 = rangeAxis.valueToJava2D(y1, dataArea, yAxisLocation);
953:
954: State s = (State) state;
955:
956: if (!Double.isNaN(transX1) && !Double.isNaN(transY1)) {
957: float x = (float) transX1;
958: float y = (float) transY1;
959: PlotOrientation orientation = plot.getOrientation();
960: if (orientation == PlotOrientation.HORIZONTAL) {
961: x = (float) transY1;
962: y = (float) transX1;
963: }
964: if (s.isLastPointGood()) {
965: s.seriesPath.lineTo(x, y);
966: }
967: else {
968: s.seriesPath.moveTo(x, y);
969: }
970: s.setLastPointGood(true);
971: }
972: else {
973: s.setLastPointGood(false);
974: }
975:
976: if (item == dataset.getItemCount(series) - 1) {
977:
978: drawFirstPassShape(g2, pass, series, item, s.seriesPath);
979: }
980: }
981:
982:
1000: protected void drawSecondaryPass(Graphics2D g2, XYPlot plot,
1001: XYDataset dataset,
1002: int pass, int series, int item,
1003: ValueAxis domainAxis,
1004: Rectangle2D dataArea,
1005: ValueAxis rangeAxis,
1006: CrosshairState crosshairState,
1007: EntityCollection entities) {
1008:
1009: Shape entityArea = null;
1010:
1011:
1012: double x1 = dataset.getXValue(series, item);
1013: double y1 = dataset.getYValue(series, item);
1014: if (Double.isNaN(y1) || Double.isNaN(x1)) {
1015: return;
1016: }
1017:
1018: PlotOrientation orientation = plot.getOrientation();
1019: RectangleEdge xAxisLocation = plot.getDomainAxisEdge();
1020: RectangleEdge yAxisLocation = plot.getRangeAxisEdge();
1021: double transX1 = domainAxis.valueToJava2D(x1, dataArea, xAxisLocation);
1022: double transY1 = rangeAxis.valueToJava2D(y1, dataArea, yAxisLocation);
1023:
1024: if (getItemShapeVisible(series, item)) {
1025: Shape shape = getItemShape(series, item);
1026: if (orientation == PlotOrientation.HORIZONTAL) {
1027: shape = ShapeUtilities.createTranslatedShape(shape, transY1,
1028: transX1);
1029: }
1030: else if (orientation == PlotOrientation.VERTICAL) {
1031: shape = ShapeUtilities.createTranslatedShape(shape, transX1,
1032: transY1);
1033: }
1034: entityArea = shape;
1035: if (shape.intersects(dataArea)) {
1036: if (getItemShapeFilled(series, item)) {
1037: if (this.useFillPaint) {
1038: g2.setPaint(getItemFillPaint(series, item));
1039: }
1040: else {
1041: g2.setPaint(getItemPaint(series, item));
1042: }
1043: g2.fill(shape);
1044: }
1045: if (this.drawOutlines) {
1046: if (getUseOutlinePaint()) {
1047: g2.setPaint(getItemOutlinePaint(series, item));
1048: }
1049: else {
1050: g2.setPaint(getItemPaint(series, item));
1051: }
1052: g2.setStroke(getItemOutlineStroke(series, item));
1053: g2.draw(shape);
1054: }
1055: }
1056: }
1057:
1058:
1059: if (isItemLabelVisible(series, item)) {
1060: double xx = transX1;
1061: double yy = transY1;
1062: if (orientation == PlotOrientation.HORIZONTAL) {
1063: xx = transY1;
1064: yy = transX1;
1065: }
1066: drawItemLabel(g2, orientation, dataset, series, item, xx, yy,
1067: (y1 < 0.0));
1068: }
1069:
1070: updateCrosshairValues(crosshairState, x1, y1, transX1, transY1,
1071: plot.getOrientation());
1072:
1073:
1074: if (entities != null) {
1075: addEntity(entities, entityArea, dataset, series, item, transX1,
1076: transY1);
1077: }
1078: }
1079:
1080:
1081:
1089: public LegendItem getLegendItem(int datasetIndex, int series) {
1090:
1091: XYPlot plot = getPlot();
1092: if (plot == null) {
1093: return null;
1094: }
1095:
1096: LegendItem result = null;
1097: XYDataset dataset = plot.getDataset(datasetIndex);
1098: if (dataset != null) {
1099: if (getItemVisible(series, 0)) {
1100: String label = getLegendItemLabelGenerator().generateLabel(
1101: dataset, series);
1102: String description = label;
1103: String toolTipText = null;
1104: if (getLegendItemToolTipGenerator() != null) {
1105: toolTipText = getLegendItemToolTipGenerator().generateLabel(
1106: dataset, series);
1107: }
1108: String urlText = null;
1109: if (getLegendItemURLGenerator() != null) {
1110: urlText = getLegendItemURLGenerator().generateLabel(
1111: dataset, series);
1112: }
1113: boolean shapeIsVisible = getItemShapeVisible(series, 0);
1114: Shape shape = getSeriesShape(series);
1115: boolean shapeIsFilled = getItemShapeFilled(series, 0);
1116: Paint fillPaint = (this.useFillPaint
1117: ? getSeriesFillPaint(series) : getSeriesPaint(series));
1118: boolean shapeOutlineVisible = this.drawOutlines;
1119: Paint outlinePaint = (this.useOutlinePaint
1120: ? getSeriesOutlinePaint(series)
1121: : getSeriesPaint(series));
1122: Stroke outlineStroke = getSeriesOutlineStroke(series);
1123: boolean lineVisible = getItemLineVisible(series, 0);
1124: Stroke lineStroke = getSeriesStroke(series);
1125: Paint linePaint = getSeriesPaint(series);
1126: result = new LegendItem(label, description, toolTipText,
1127: urlText, shapeIsVisible, shape, shapeIsFilled,
1128: fillPaint, shapeOutlineVisible, outlinePaint,
1129: outlineStroke, lineVisible, this.legendLine,
1130: lineStroke, linePaint);
1131: result.setSeriesIndex(series);
1132: result.setDatasetIndex(datasetIndex);
1133: }
1134: }
1135:
1136: return result;
1137:
1138: }
1139:
1140:
1147: public Object clone() throws CloneNotSupportedException {
1148: return super.clone();
1149: }
1150:
1151:
1158: public boolean equals(Object obj) {
1159:
1160: if (obj == this) {
1161: return true;
1162: }
1163: if (!(obj instanceof XYLineAndShapeRenderer)) {
1164: return false;
1165: }
1166: if (!super.equals(obj)) {
1167: return false;
1168: }
1169: XYLineAndShapeRenderer that = (XYLineAndShapeRenderer) obj;
1170: if (!ObjectUtilities.equal(this.linesVisible, that.linesVisible)) {
1171: return false;
1172: }
1173: if (!ObjectUtilities.equal(
1174: this.seriesLinesVisible, that.seriesLinesVisible)
1175: ) {
1176: return false;
1177: }
1178: if (this.baseLinesVisible != that.baseLinesVisible) {
1179: return false;
1180: }
1181: if (!ShapeUtilities.equal(this.legendLine, that.legendLine)) {
1182: return false;
1183: }
1184: if (!ObjectUtilities.equal(this.shapesVisible, that.shapesVisible)) {
1185: return false;
1186: }
1187: if (!ObjectUtilities.equal(
1188: this.seriesShapesVisible, that.seriesShapesVisible)
1189: ) {
1190: return false;
1191: }
1192: if (this.baseShapesVisible != that.baseShapesVisible) {
1193: return false;
1194: }
1195: if (!ObjectUtilities.equal(this.shapesFilled, that.shapesFilled)) {
1196: return false;
1197: }
1198: if (!ObjectUtilities.equal(
1199: this.seriesShapesFilled, that.seriesShapesFilled)
1200: ) {
1201: return false;
1202: }
1203: if (this.baseShapesFilled != that.baseShapesFilled) {
1204: return false;
1205: }
1206: if (this.drawOutlines != that.drawOutlines) {
1207: return false;
1208: }
1209: if (this.useOutlinePaint != that.useOutlinePaint) {
1210: return false;
1211: }
1212:
1213: return true;
1214:
1215: }
1216:
1217:
1225: private void readObject(ObjectInputStream stream)
1226: throws IOException, ClassNotFoundException {
1227: stream.defaultReadObject();
1228: this.legendLine = SerialUtilities.readShape(stream);
1229: }
1230:
1231:
1238: private void writeObject(ObjectOutputStream stream) throws IOException {
1239: stream.defaultWriteObject();
1240: SerialUtilities.writeShape(this.legendLine, stream);
1241: }
1242:
1243: }