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