1:
54:
55: package ;
56:
57: import ;
58: import ;
59: import ;
60: import ;
61: import ;
62: import ;
63: import ;
64: import ;
65: import ;
66:
67: import ;
68: import ;
69: import ;
70: import ;
71: import ;
72: import ;
73: import ;
74: import ;
75: import ;
76: import ;
77: import ;
78: import ;
79:
80:
83: public class CombinedRangeCategoryPlot extends CategoryPlot
84: implements Zoomable,
85: Cloneable, PublicCloneable,
86: Serializable,
87: PlotChangeListener {
88:
89:
90: private static final long serialVersionUID = 7260210007554504515L;
91:
92:
93: private List subplots;
94:
95:
96: private int totalWeight;
97:
98:
99: private double gap;
100:
101:
102: private transient Rectangle2D[] subplotArea;
103:
104:
107: public CombinedRangeCategoryPlot() {
108: this(new NumberAxis());
109: }
110:
111:
116: public CombinedRangeCategoryPlot(ValueAxis rangeAxis) {
117: super(null, null, rangeAxis, null);
118: this.subplots = new java.util.ArrayList();
119: this.totalWeight = 0;
120: this.gap = 5.0;
121: }
122:
123:
128: public double getGap() {
129: return this.gap;
130: }
131:
132:
138: public void setGap(double gap) {
139: this.gap = gap;
140: notifyListeners(new PlotChangeEvent(this));
141: }
142:
143:
152: public void add(CategoryPlot subplot) {
153:
154: add(subplot, 1);
155: }
156:
157:
167: public void add(CategoryPlot subplot, int weight) {
168: if (subplot == null) {
169: throw new IllegalArgumentException("Null 'subplot' argument.");
170: }
171: if (weight <= 0) {
172: throw new IllegalArgumentException("Require weight >= 1.");
173: }
174:
175: subplot.setParent(this);
176: subplot.setWeight(weight);
177: subplot.setInsets(new RectangleInsets(0.0, 0.0, 0.0, 0.0));
178: subplot.setRangeAxis(null);
179: subplot.setOrientation(getOrientation());
180: subplot.addChangeListener(this);
181: this.subplots.add(subplot);
182: this.totalWeight += weight;
183:
184:
185: ValueAxis axis = getRangeAxis();
186: if (axis != null) {
187: axis.configure();
188: }
189: notifyListeners(new PlotChangeEvent(this));
190: }
191:
192:
197: public void remove(CategoryPlot subplot) {
198: if (subplot == null) {
199: throw new IllegalArgumentException(" Null 'subplot' argument.");
200: }
201: int position = -1;
202: int size = this.subplots.size();
203: int i = 0;
204: while (position == -1 && i < size) {
205: if (this.subplots.get(i) == subplot) {
206: position = i;
207: }
208: i++;
209: }
210: if (position != -1) {
211: this.subplots.remove(position);
212: subplot.setParent(null);
213: subplot.removeChangeListener(this);
214: this.totalWeight -= subplot.getWeight();
215:
216: ValueAxis range = getRangeAxis();
217: if (range != null) {
218: range.configure();
219: }
220:
221: ValueAxis range2 = getRangeAxis(1);
222: if (range2 != null) {
223: range2.configure();
224: }
225: notifyListeners(new PlotChangeEvent(this));
226: }
227: }
228:
229:
234: public List getSubplots() {
235: return Collections.unmodifiableList(this.subplots);
236: }
237:
238:
246: protected AxisSpace calculateAxisSpace(Graphics2D g2,
247: Rectangle2D plotArea) {
248:
249: AxisSpace space = new AxisSpace();
250: PlotOrientation orientation = getOrientation();
251:
252:
253: AxisSpace fixed = getFixedRangeAxisSpace();
254: if (fixed != null) {
255: if (orientation == PlotOrientation.VERTICAL) {
256: space.setLeft(fixed.getLeft());
257: space.setRight(fixed.getRight());
258: }
259: else if (orientation == PlotOrientation.HORIZONTAL) {
260: space.setTop(fixed.getTop());
261: space.setBottom(fixed.getBottom());
262: }
263: }
264: else {
265: ValueAxis valueAxis = getRangeAxis();
266: RectangleEdge valueEdge = Plot.resolveRangeAxisLocation(
267: getRangeAxisLocation(), orientation);
268: if (valueAxis != null) {
269: space = valueAxis.reserveSpace(g2, this, plotArea, valueEdge,
270: space);
271: }
272: }
273:
274: Rectangle2D adjustedPlotArea = space.shrink(plotArea, null);
275:
276: int n = this.subplots.size();
277:
278:
279:
280: this.subplotArea = new Rectangle2D[n];
281: double x = adjustedPlotArea.getX();
282: double y = adjustedPlotArea.getY();
283: double usableSize = 0.0;
284: if (orientation == PlotOrientation.VERTICAL) {
285: usableSize = adjustedPlotArea.getWidth() - this.gap * (n - 1);
286: }
287: else if (orientation == PlotOrientation.HORIZONTAL) {
288: usableSize = adjustedPlotArea.getHeight() - this.gap * (n - 1);
289: }
290:
291: for (int i = 0; i < n; i++) {
292: CategoryPlot plot = (CategoryPlot) this.subplots.get(i);
293:
294:
295: if (orientation == PlotOrientation.VERTICAL) {
296: double w = usableSize * plot.getWeight() / this.totalWeight;
297: this.subplotArea[i] = new Rectangle2D.Double(x, y, w,
298: adjustedPlotArea.getHeight());
299: x = x + w + this.gap;
300: }
301: else if (orientation == PlotOrientation.HORIZONTAL) {
302: double h = usableSize * plot.getWeight() / this.totalWeight;
303: this.subplotArea[i] = new Rectangle2D.Double(x, y,
304: adjustedPlotArea.getWidth(), h);
305: y = y + h + this.gap;
306: }
307:
308: AxisSpace subSpace = plot.calculateDomainAxisSpace(g2,
309: this.subplotArea[i], null);
310: space.ensureAtLeast(subSpace);
311:
312: }
313:
314: return space;
315: }
316:
317:
330: public void draw(Graphics2D g2, Rectangle2D area, Point2D anchor,
331: PlotState parentState,
332: PlotRenderingInfo info) {
333:
334:
335: if (info != null) {
336: info.setPlotArea(area);
337: }
338:
339:
340: RectangleInsets insets = getInsets();
341: insets.trim(area);
342:
343:
344: AxisSpace space = calculateAxisSpace(g2, area);
345: Rectangle2D dataArea = space.shrink(area, null);
346:
347:
348: setFixedDomainAxisSpaceForSubplots(space);
349:
350:
351: ValueAxis axis = getRangeAxis();
352: RectangleEdge rangeEdge = getRangeAxisEdge();
353: double cursor = RectangleEdge.coordinate(dataArea, rangeEdge);
354: AxisState state = axis.draw(g2, cursor, area, dataArea, rangeEdge,
355: info);
356: if (parentState == null) {
357: parentState = new PlotState();
358: }
359: parentState.getSharedAxisStates().put(axis, state);
360:
361:
362: for (int i = 0; i < this.subplots.size(); i++) {
363: CategoryPlot plot = (CategoryPlot) this.subplots.get(i);
364: PlotRenderingInfo subplotInfo = null;
365: if (info != null) {
366: subplotInfo = new PlotRenderingInfo(info.getOwner());
367: info.addSubplotInfo(subplotInfo);
368: }
369: plot.draw(g2, this.subplotArea[i], null, parentState, subplotInfo);
370: }
371:
372: if (info != null) {
373: info.setDataArea(dataArea);
374: }
375:
376: }
377:
378:
383: public void setOrientation(PlotOrientation orientation) {
384:
385: super.setOrientation(orientation);
386:
387: Iterator iterator = this.subplots.iterator();
388: while (iterator.hasNext()) {
389: CategoryPlot plot = (CategoryPlot) iterator.next();
390: plot.setOrientation(orientation);
391: }
392:
393: }
394:
395:
403: public Range getDataRange(ValueAxis axis) {
404:
405: Range result = null;
406: if (this.subplots != null) {
407: Iterator iterator = this.subplots.iterator();
408: while (iterator.hasNext()) {
409: CategoryPlot subplot = (CategoryPlot) iterator.next();
410: result = Range.combine(result, subplot.getDataRange(axis));
411: }
412: }
413: return result;
414:
415: }
416:
417:
422: public LegendItemCollection getLegendItems() {
423: LegendItemCollection result = getFixedLegendItems();
424: if (result == null) {
425: result = new LegendItemCollection();
426: if (this.subplots != null) {
427: Iterator iterator = this.subplots.iterator();
428: while (iterator.hasNext()) {
429: CategoryPlot plot = (CategoryPlot) iterator.next();
430: LegendItemCollection more = plot.getLegendItems();
431: result.addAll(more);
432: }
433: }
434: }
435: return result;
436: }
437:
438:
444: protected void setFixedDomainAxisSpaceForSubplots(AxisSpace space) {
445: Iterator iterator = this.subplots.iterator();
446: while (iterator.hasNext()) {
447: CategoryPlot plot = (CategoryPlot) iterator.next();
448: plot.setFixedDomainAxisSpace(space, false);
449: }
450: }
451:
452:
460: public void handleClick(int x, int y, PlotRenderingInfo info) {
461:
462: Rectangle2D dataArea = info.getDataArea();
463: if (dataArea.contains(x, y)) {
464: for (int i = 0; i < this.subplots.size(); i++) {
465: CategoryPlot subplot = (CategoryPlot) this.subplots.get(i);
466: PlotRenderingInfo subplotInfo = info.getSubplotInfo(i);
467: subplot.handleClick(x, y, subplotInfo);
468: }
469: }
470:
471: }
472:
473:
479: public void plotChanged(PlotChangeEvent event) {
480: notifyListeners(event);
481: }
482:
483:
490: public boolean equals(Object obj) {
491: if (obj == this) {
492: return true;
493: }
494: if (!(obj instanceof CombinedRangeCategoryPlot)) {
495: return false;
496: }
497: if (!super.equals(obj)) {
498: return false;
499: }
500: CombinedRangeCategoryPlot that = (CombinedRangeCategoryPlot) obj;
501: if (!ObjectUtilities.equal(this.subplots, that.subplots)) {
502: return false;
503: }
504: if (this.totalWeight != that.totalWeight) {
505: return false;
506: }
507: if (this.gap != that.gap) {
508: return false;
509: }
510: return true;
511: }
512:
513:
521: public Object clone() throws CloneNotSupportedException {
522: CombinedRangeCategoryPlot result
523: = (CombinedRangeCategoryPlot) super.clone();
524: result.subplots = (List) ObjectUtilities.deepClone(this.subplots);
525: for (Iterator it = result.subplots.iterator(); it.hasNext();) {
526: Plot child = (Plot) it.next();
527: child.setParent(result);
528: }
529:
530:
531:
532: ValueAxis rangeAxis = result.getRangeAxis();
533: if (rangeAxis != null) {
534: rangeAxis.configure();
535: }
536:
537: return result;
538: }
539:
540:
548: private void readObject(ObjectInputStream stream)
549: throws IOException, ClassNotFoundException {
550:
551: stream.defaultReadObject();
552:
553:
554:
555: ValueAxis rangeAxis = getRangeAxis();
556: if (rangeAxis != null) {
557: rangeAxis.configure();
558: }
559:
560: }
561:
562: }