1:
58:
59: package ;
60:
61: import ;
62: import ;
63: import ;
64: import ;
65: import ;
66: import ;
67: import ;
68: import ;
69:
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 PlotChangeListener {
87:
88:
89: private static final long serialVersionUID = 7260210007554504515L;
90:
91:
92: private List subplots;
93:
94:
95: private int totalWeight;
96:
97:
98: private double gap;
99:
100:
101: private transient Rectangle2D[] subplotArea;
102:
103:
106: public CombinedRangeCategoryPlot() {
107: this(new NumberAxis());
108: }
109:
110:
115: public CombinedRangeCategoryPlot(ValueAxis rangeAxis) {
116: super(null, null, rangeAxis, null);
117: this.subplots = new java.util.ArrayList();
118: this.totalWeight = 0;
119: this.gap = 5.0;
120: }
121:
122:
127: public double getGap() {
128: return this.gap;
129: }
130:
131:
137: public void setGap(double gap) {
138: this.gap = gap;
139: fireChangeEvent();
140: }
141:
142:
151: public void add(CategoryPlot subplot) {
152:
153: add(subplot, 1);
154: }
155:
156:
166: public void add(CategoryPlot subplot, int weight) {
167: if (subplot == null) {
168: throw new IllegalArgumentException("Null 'subplot' argument.");
169: }
170: if (weight <= 0) {
171: throw new IllegalArgumentException("Require weight >= 1.");
172: }
173:
174: subplot.setParent(this);
175: subplot.setWeight(weight);
176: subplot.setInsets(new RectangleInsets(0.0, 0.0, 0.0, 0.0));
177: subplot.setRangeAxis(null);
178: subplot.setOrientation(getOrientation());
179: subplot.addChangeListener(this);
180: this.subplots.add(subplot);
181: this.totalWeight += weight;
182:
183:
184: ValueAxis axis = getRangeAxis();
185: if (axis != null) {
186: axis.configure();
187: }
188: fireChangeEvent();
189: }
190:
191:
196: public void remove(CategoryPlot subplot) {
197: if (subplot == null) {
198: throw new IllegalArgumentException(" Null 'subplot' argument.");
199: }
200: int position = -1;
201: int size = this.subplots.size();
202: int i = 0;
203: while (position == -1 && i < size) {
204: if (this.subplots.get(i) == subplot) {
205: position = i;
206: }
207: i++;
208: }
209: if (position != -1) {
210: this.subplots.remove(position);
211: subplot.setParent(null);
212: subplot.removeChangeListener(this);
213: this.totalWeight -= subplot.getWeight();
214:
215: ValueAxis range = getRangeAxis();
216: if (range != null) {
217: range.configure();
218: }
219:
220: ValueAxis range2 = getRangeAxis(1);
221: if (range2 != null) {
222: range2.configure();
223: }
224: fireChangeEvent();
225: }
226: }
227:
228:
234: public List getSubplots() {
235: if (this.subplots != null) {
236: return Collections.unmodifiableList(this.subplots);
237: }
238: else {
239: return Collections.EMPTY_LIST;
240: }
241: }
242:
243:
251: protected AxisSpace calculateAxisSpace(Graphics2D g2,
252: Rectangle2D plotArea) {
253:
254: AxisSpace space = new AxisSpace();
255: PlotOrientation orientation = getOrientation();
256:
257:
258: AxisSpace fixed = getFixedRangeAxisSpace();
259: if (fixed != null) {
260: if (orientation == PlotOrientation.VERTICAL) {
261: space.setLeft(fixed.getLeft());
262: space.setRight(fixed.getRight());
263: }
264: else if (orientation == PlotOrientation.HORIZONTAL) {
265: space.setTop(fixed.getTop());
266: space.setBottom(fixed.getBottom());
267: }
268: }
269: else {
270: ValueAxis valueAxis = getRangeAxis();
271: RectangleEdge valueEdge = Plot.resolveRangeAxisLocation(
272: getRangeAxisLocation(), orientation);
273: if (valueAxis != null) {
274: space = valueAxis.reserveSpace(g2, this, plotArea, valueEdge,
275: space);
276: }
277: }
278:
279: Rectangle2D adjustedPlotArea = space.shrink(plotArea, null);
280:
281: int n = this.subplots.size();
282:
283:
284:
285: this.subplotArea = new Rectangle2D[n];
286: double x = adjustedPlotArea.getX();
287: double y = adjustedPlotArea.getY();
288: double usableSize = 0.0;
289: if (orientation == PlotOrientation.VERTICAL) {
290: usableSize = adjustedPlotArea.getWidth() - this.gap * (n - 1);
291: }
292: else if (orientation == PlotOrientation.HORIZONTAL) {
293: usableSize = adjustedPlotArea.getHeight() - this.gap * (n - 1);
294: }
295:
296: for (int i = 0; i < n; i++) {
297: CategoryPlot plot = (CategoryPlot) this.subplots.get(i);
298:
299:
300: if (orientation == PlotOrientation.VERTICAL) {
301: double w = usableSize * plot.getWeight() / this.totalWeight;
302: this.subplotArea[i] = new Rectangle2D.Double(x, y, w,
303: adjustedPlotArea.getHeight());
304: x = x + w + this.gap;
305: }
306: else if (orientation == PlotOrientation.HORIZONTAL) {
307: double h = usableSize * plot.getWeight() / this.totalWeight;
308: this.subplotArea[i] = new Rectangle2D.Double(x, y,
309: adjustedPlotArea.getWidth(), h);
310: y = y + h + this.gap;
311: }
312:
313: AxisSpace subSpace = plot.calculateDomainAxisSpace(g2,
314: this.subplotArea[i], null);
315: space.ensureAtLeast(subSpace);
316:
317: }
318:
319: return space;
320: }
321:
322:
335: public void draw(Graphics2D g2, Rectangle2D area, Point2D anchor,
336: PlotState parentState,
337: PlotRenderingInfo info) {
338:
339:
340: if (info != null) {
341: info.setPlotArea(area);
342: }
343:
344:
345: RectangleInsets insets = getInsets();
346: insets.trim(area);
347:
348:
349: AxisSpace space = calculateAxisSpace(g2, area);
350: Rectangle2D dataArea = space.shrink(area, null);
351:
352:
353: setFixedDomainAxisSpaceForSubplots(space);
354:
355:
356: ValueAxis axis = getRangeAxis();
357: RectangleEdge rangeEdge = getRangeAxisEdge();
358: double cursor = RectangleEdge.coordinate(dataArea, rangeEdge);
359: AxisState state = axis.draw(g2, cursor, area, dataArea, rangeEdge,
360: info);
361: if (parentState == null) {
362: parentState = new PlotState();
363: }
364: parentState.getSharedAxisStates().put(axis, state);
365:
366:
367: for (int i = 0; i < this.subplots.size(); i++) {
368: CategoryPlot plot = (CategoryPlot) this.subplots.get(i);
369: PlotRenderingInfo subplotInfo = null;
370: if (info != null) {
371: subplotInfo = new PlotRenderingInfo(info.getOwner());
372: info.addSubplotInfo(subplotInfo);
373: }
374: plot.draw(g2, this.subplotArea[i], null, parentState, subplotInfo);
375: }
376:
377: if (info != null) {
378: info.setDataArea(dataArea);
379: }
380:
381: }
382:
383:
388: public void setOrientation(PlotOrientation orientation) {
389:
390: super.setOrientation(orientation);
391:
392: Iterator iterator = this.subplots.iterator();
393: while (iterator.hasNext()) {
394: CategoryPlot plot = (CategoryPlot) iterator.next();
395: plot.setOrientation(orientation);
396: }
397:
398: }
399:
400:
413: public Range getDataRange(ValueAxis axis) {
414: Range result = null;
415: if (this.subplots != null) {
416: Iterator iterator = this.subplots.iterator();
417: while (iterator.hasNext()) {
418: CategoryPlot subplot = (CategoryPlot) iterator.next();
419: result = Range.combine(result, subplot.getDataRange(axis));
420: }
421: }
422: return result;
423: }
424:
425:
430: public LegendItemCollection getLegendItems() {
431: LegendItemCollection result = getFixedLegendItems();
432: if (result == null) {
433: result = new LegendItemCollection();
434: if (this.subplots != null) {
435: Iterator iterator = this.subplots.iterator();
436: while (iterator.hasNext()) {
437: CategoryPlot plot = (CategoryPlot) iterator.next();
438: LegendItemCollection more = plot.getLegendItems();
439: result.addAll(more);
440: }
441: }
442: }
443: return result;
444: }
445:
446:
452: protected void setFixedDomainAxisSpaceForSubplots(AxisSpace space) {
453: Iterator iterator = this.subplots.iterator();
454: while (iterator.hasNext()) {
455: CategoryPlot plot = (CategoryPlot) iterator.next();
456: plot.setFixedDomainAxisSpace(space, false);
457: }
458: }
459:
460:
468: public void handleClick(int x, int y, PlotRenderingInfo info) {
469:
470: Rectangle2D dataArea = info.getDataArea();
471: if (dataArea.contains(x, y)) {
472: for (int i = 0; i < this.subplots.size(); i++) {
473: CategoryPlot subplot = (CategoryPlot) this.subplots.get(i);
474: PlotRenderingInfo subplotInfo = info.getSubplotInfo(i);
475: subplot.handleClick(x, y, subplotInfo);
476: }
477: }
478:
479: }
480:
481:
487: public void plotChanged(PlotChangeEvent event) {
488: notifyListeners(event);
489: }
490:
491:
498: public boolean equals(Object obj) {
499: if (obj == this) {
500: return true;
501: }
502: if (!(obj instanceof CombinedRangeCategoryPlot)) {
503: return false;
504: }
505: if (!super.equals(obj)) {
506: return false;
507: }
508: CombinedRangeCategoryPlot that = (CombinedRangeCategoryPlot) obj;
509: if (!ObjectUtilities.equal(this.subplots, that.subplots)) {
510: return false;
511: }
512: if (this.totalWeight != that.totalWeight) {
513: return false;
514: }
515: if (this.gap != that.gap) {
516: return false;
517: }
518: return true;
519: }
520:
521:
529: public Object clone() throws CloneNotSupportedException {
530: CombinedRangeCategoryPlot result
531: = (CombinedRangeCategoryPlot) super.clone();
532: result.subplots = (List) ObjectUtilities.deepClone(this.subplots);
533: for (Iterator it = result.subplots.iterator(); it.hasNext();) {
534: Plot child = (Plot) it.next();
535: child.setParent(result);
536: }
537:
538:
539:
540: ValueAxis rangeAxis = result.getRangeAxis();
541: if (rangeAxis != null) {
542: rangeAxis.configure();
543: }
544:
545: return result;
546: }
547:
548:
556: private void readObject(ObjectInputStream stream)
557: throws IOException, ClassNotFoundException {
558:
559: stream.defaultReadObject();
560:
561:
562:
563: ValueAxis rangeAxis = getRangeAxis();
564: if (rangeAxis != null) {
565: rangeAxis.configure();
566: }
567:
568: }
569:
570: }