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:
151: public void add(CategoryPlot subplot) {
152:
153: add(subplot, 1);
154: }
155:
156:
163: public void add(CategoryPlot subplot, int weight) {
164: if (subplot == null) {
165: throw new IllegalArgumentException("Null 'subplot' argument.");
166: }
167: if (weight <= 0) {
168: throw new IllegalArgumentException("Require weight >= 1.");
169: }
170:
171: subplot.setParent(this);
172: subplot.setWeight(weight);
173: subplot.setInsets(new RectangleInsets(0.0, 0.0, 0.0, 0.0));
174: subplot.setRangeAxis(null);
175: subplot.setOrientation(getOrientation());
176: subplot.addChangeListener(this);
177: this.subplots.add(subplot);
178: this.totalWeight += weight;
179:
180:
181: ValueAxis axis = getRangeAxis();
182: if (axis != null) {
183: axis.configure();
184: }
185: notifyListeners(new PlotChangeEvent(this));
186: }
187:
188:
193: public void remove(CategoryPlot subplot) {
194: if (subplot == null) {
195: throw new IllegalArgumentException(" Null 'subplot' argument.");
196: }
197: int position = -1;
198: int size = this.subplots.size();
199: int i = 0;
200: while (position == -1 && i < size) {
201: if (this.subplots.get(i) == subplot) {
202: position = i;
203: }
204: i++;
205: }
206: if (position != -1) {
207: this.subplots.remove(position);
208: subplot.setParent(null);
209: subplot.removeChangeListener(this);
210: this.totalWeight -= subplot.getWeight();
211:
212: ValueAxis range = getRangeAxis();
213: if (range != null) {
214: range.configure();
215: }
216:
217: ValueAxis range2 = getRangeAxis(1);
218: if (range2 != null) {
219: range2.configure();
220: }
221: notifyListeners(new PlotChangeEvent(this));
222: }
223: }
224:
225:
230: public List getSubplots() {
231: return Collections.unmodifiableList(this.subplots);
232: }
233:
234:
242: protected AxisSpace calculateAxisSpace(Graphics2D g2,
243: Rectangle2D plotArea) {
244:
245: AxisSpace space = new AxisSpace();
246: PlotOrientation orientation = getOrientation();
247:
248:
249: AxisSpace fixed = getFixedRangeAxisSpace();
250: if (fixed != null) {
251: if (orientation == PlotOrientation.VERTICAL) {
252: space.setLeft(fixed.getLeft());
253: space.setRight(fixed.getRight());
254: }
255: else if (orientation == PlotOrientation.HORIZONTAL) {
256: space.setTop(fixed.getTop());
257: space.setBottom(fixed.getBottom());
258: }
259: }
260: else {
261: ValueAxis valueAxis = getRangeAxis();
262: RectangleEdge valueEdge = Plot.resolveRangeAxisLocation(
263: getRangeAxisLocation(), orientation
264: );
265: if (valueAxis != null) {
266: space = valueAxis.reserveSpace(
267: g2, this, plotArea, valueEdge, space
268: );
269: }
270: }
271:
272: Rectangle2D adjustedPlotArea = space.shrink(plotArea, null);
273:
274: int n = this.subplots.size();
275:
276:
277:
278: this.subplotArea = new Rectangle2D[n];
279: double x = adjustedPlotArea.getX();
280: double y = adjustedPlotArea.getY();
281: double usableSize = 0.0;
282: if (orientation == PlotOrientation.VERTICAL) {
283: usableSize = adjustedPlotArea.getWidth() - this.gap * (n - 1);
284: }
285: else if (orientation == PlotOrientation.HORIZONTAL) {
286: usableSize = adjustedPlotArea.getHeight() - this.gap * (n - 1);
287: }
288:
289: for (int i = 0; i < n; i++) {
290: CategoryPlot plot = (CategoryPlot) this.subplots.get(i);
291:
292:
293: if (orientation == PlotOrientation.VERTICAL) {
294: double w = usableSize * plot.getWeight() / this.totalWeight;
295: this.subplotArea[i] = new Rectangle2D.Double(
296: x, y, w, adjustedPlotArea.getHeight()
297: );
298: x = x + w + this.gap;
299: }
300: else if (orientation == PlotOrientation.HORIZONTAL) {
301: double h = usableSize * plot.getWeight() / this.totalWeight;
302: this.subplotArea[i] = new Rectangle2D.Double(
303: x, y, adjustedPlotArea.getWidth(), h
304: );
305: y = y + h + this.gap;
306: }
307:
308: AxisSpace subSpace = plot.calculateDomainAxisSpace(
309: g2, this.subplotArea[i], null
310: );
311: space.ensureAtLeast(subSpace);
312:
313: }
314:
315: return space;
316: }
317:
318:
331: public void draw(Graphics2D g2, Rectangle2D area, Point2D anchor,
332: PlotState parentState,
333: PlotRenderingInfo info) {
334:
335:
336: if (info != null) {
337: info.setPlotArea(area);
338: }
339:
340:
341: RectangleInsets insets = getInsets();
342: insets.trim(area);
343:
344:
345: AxisSpace space = calculateAxisSpace(g2, area);
346: Rectangle2D dataArea = space.shrink(area, null);
347:
348:
349: setFixedDomainAxisSpaceForSubplots(space);
350:
351:
352: ValueAxis axis = getRangeAxis();
353: RectangleEdge rangeEdge = getRangeAxisEdge();
354: double cursor = RectangleEdge.coordinate(dataArea, rangeEdge);
355: AxisState state = axis.draw(
356: g2, cursor, area, dataArea, rangeEdge, info
357: );
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: }