1:
58:
59: package ;
60:
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:
80:
83: public class CombinedDomainCategoryPlot extends CategoryPlot
84: implements Zoomable,
85: Cloneable, PublicCloneable,
86: Serializable,
87: PlotChangeListener {
88:
89:
90: private static final long serialVersionUID = 8207194522653701572L;
91:
92:
93: private List subplots;
94:
95:
96: private int totalWeight;
97:
98:
99: private double gap;
100:
101:
102: private transient Rectangle2D[] subplotAreas;
103:
104:
105:
108: public CombinedDomainCategoryPlot() {
109: this(new CategoryAxis());
110: }
111:
112:
118: public CombinedDomainCategoryPlot(CategoryAxis domainAxis) {
119: super(null, domainAxis, null, 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: add(subplot, 1);
156: }
157:
158:
168: public void add(CategoryPlot subplot, int weight) {
169: if (subplot == null) {
170: throw new IllegalArgumentException("Null 'subplot' argument.");
171: }
172: if (weight < 1) {
173: throw new IllegalArgumentException("Require weight >= 1.");
174: }
175: subplot.setParent(this);
176: subplot.setWeight(weight);
177: subplot.setInsets(new RectangleInsets(0.0, 0.0, 0.0, 0.0));
178: subplot.setDomainAxis(null);
179: subplot.setOrientation(getOrientation());
180: subplot.addChangeListener(this);
181: this.subplots.add(subplot);
182: this.totalWeight += weight;
183: CategoryAxis axis = getDomainAxis();
184: if (axis != null) {
185: axis.configure();
186: }
187: notifyListeners(new PlotChangeEvent(this));
188: }
189:
190:
198: public void remove(CategoryPlot subplot) {
199: if (subplot == null) {
200: throw new IllegalArgumentException("Null 'subplot' argument.");
201: }
202: int position = -1;
203: int size = this.subplots.size();
204: int i = 0;
205: while (position == -1 && i < size) {
206: if (this.subplots.get(i) == subplot) {
207: position = i;
208: }
209: i++;
210: }
211: if (position != -1) {
212: this.subplots.remove(position);
213: subplot.setParent(null);
214: subplot.removeChangeListener(this);
215: this.totalWeight -= subplot.getWeight();
216:
217: CategoryAxis domain = getDomainAxis();
218: if (domain != null) {
219: domain.configure();
220: }
221: notifyListeners(new PlotChangeEvent(this));
222: }
223: }
224:
225:
230: public List getSubplots() {
231: return Collections.unmodifiableList(this.subplots);
232: }
233:
234:
243: public CategoryPlot findSubplot(PlotRenderingInfo info, Point2D source) {
244: CategoryPlot result = null;
245: int subplotIndex = info.getSubplotIndex(source);
246: if (subplotIndex >= 0) {
247: result = (CategoryPlot) this.subplots.get(subplotIndex);
248: }
249: return result;
250: }
251:
252:
259: public void zoomRangeAxes(double factor, PlotRenderingInfo info,
260: Point2D source) {
261: CategoryPlot subplot = findSubplot(info, source);
262: if (subplot != null) {
263: subplot.zoomRangeAxes(factor, info, source);
264: }
265: }
266:
267:
275: public void zoomRangeAxes(double lowerPercent, double upperPercent,
276: PlotRenderingInfo info, Point2D source) {
277: CategoryPlot subplot = findSubplot(info, source);
278: if (subplot != null) {
279: subplot.zoomRangeAxes(lowerPercent, upperPercent, info, source);
280: }
281: }
282:
283:
291: protected AxisSpace calculateAxisSpace(Graphics2D g2,
292: Rectangle2D plotArea) {
293:
294: AxisSpace space = new AxisSpace();
295: PlotOrientation orientation = getOrientation();
296:
297:
298: AxisSpace fixed = getFixedDomainAxisSpace();
299: if (fixed != null) {
300: if (orientation == PlotOrientation.HORIZONTAL) {
301: space.setLeft(fixed.getLeft());
302: space.setRight(fixed.getRight());
303: }
304: else if (orientation == PlotOrientation.VERTICAL) {
305: space.setTop(fixed.getTop());
306: space.setBottom(fixed.getBottom());
307: }
308: }
309: else {
310: CategoryAxis categoryAxis = getDomainAxis();
311: RectangleEdge categoryEdge = Plot.resolveDomainAxisLocation(
312: getDomainAxisLocation(), orientation);
313: if (categoryAxis != null) {
314: space = categoryAxis.reserveSpace(g2, this, plotArea,
315: categoryEdge, space);
316: }
317: else {
318: if (getDrawSharedDomainAxis()) {
319: space = getDomainAxis().reserveSpace(g2, this, plotArea,
320: categoryEdge, space);
321: }
322: }
323: }
324:
325: Rectangle2D adjustedPlotArea = space.shrink(plotArea, null);
326:
327:
328: int n = this.subplots.size();
329: this.subplotAreas = new Rectangle2D[n];
330: double x = adjustedPlotArea.getX();
331: double y = adjustedPlotArea.getY();
332: double usableSize = 0.0;
333: if (orientation == PlotOrientation.HORIZONTAL) {
334: usableSize = adjustedPlotArea.getWidth() - this.gap * (n - 1);
335: }
336: else if (orientation == PlotOrientation.VERTICAL) {
337: usableSize = adjustedPlotArea.getHeight() - this.gap * (n - 1);
338: }
339:
340: for (int i = 0; i < n; i++) {
341: CategoryPlot plot = (CategoryPlot) this.subplots.get(i);
342:
343:
344: if (orientation == PlotOrientation.HORIZONTAL) {
345: double w = usableSize * plot.getWeight() / this.totalWeight;
346: this.subplotAreas[i] = new Rectangle2D.Double(x, y, w,
347: adjustedPlotArea.getHeight());
348: x = x + w + this.gap;
349: }
350: else if (orientation == PlotOrientation.VERTICAL) {
351: double h = usableSize * plot.getWeight() / this.totalWeight;
352: this.subplotAreas[i] = new Rectangle2D.Double(x, y,
353: adjustedPlotArea.getWidth(), h);
354: y = y + h + this.gap;
355: }
356:
357: AxisSpace subSpace = plot.calculateRangeAxisSpace(g2,
358: this.subplotAreas[i], null);
359: space.ensureAtLeast(subSpace);
360:
361: }
362:
363: return space;
364: }
365:
366:
379: public void draw(Graphics2D g2,
380: Rectangle2D area,
381: Point2D anchor,
382: PlotState parentState,
383: PlotRenderingInfo info) {
384:
385:
386: if (info != null) {
387: info.setPlotArea(area);
388: }
389:
390:
391: RectangleInsets insets = getInsets();
392: area.setRect(area.getX() + insets.getLeft(),
393: area.getY() + insets.getTop(),
394: area.getWidth() - insets.getLeft() - insets.getRight(),
395: area.getHeight() - insets.getTop() - insets.getBottom());
396:
397:
398:
399: setFixedRangeAxisSpaceForSubplots(null);
400: AxisSpace space = calculateAxisSpace(g2, area);
401: Rectangle2D dataArea = space.shrink(area, null);
402:
403:
404: setFixedRangeAxisSpaceForSubplots(space);
405:
406:
407: CategoryAxis axis = getDomainAxis();
408: RectangleEdge domainEdge = getDomainAxisEdge();
409: double cursor = RectangleEdge.coordinate(dataArea, domainEdge);
410: AxisState axisState = axis.draw(g2, cursor, area, dataArea,
411: domainEdge, info);
412: if (parentState == null) {
413: parentState = new PlotState();
414: }
415: parentState.getSharedAxisStates().put(axis, axisState);
416:
417:
418: for (int i = 0; i < this.subplots.size(); i++) {
419: CategoryPlot plot = (CategoryPlot) this.subplots.get(i);
420: PlotRenderingInfo subplotInfo = null;
421: if (info != null) {
422: subplotInfo = new PlotRenderingInfo(info.getOwner());
423: info.addSubplotInfo(subplotInfo);
424: }
425: plot.draw(g2, this.subplotAreas[i], null, parentState, subplotInfo);
426: }
427:
428: if (info != null) {
429: info.setDataArea(dataArea);
430: }
431:
432: }
433:
434:
440: protected void setFixedRangeAxisSpaceForSubplots(AxisSpace space) {
441:
442: Iterator iterator = this.subplots.iterator();
443: while (iterator.hasNext()) {
444: CategoryPlot plot = (CategoryPlot) iterator.next();
445: plot.setFixedRangeAxisSpace(space);
446: }
447:
448: }
449:
450:
455: public void setOrientation(PlotOrientation orientation) {
456:
457: super.setOrientation(orientation);
458:
459: Iterator iterator = this.subplots.iterator();
460: while (iterator.hasNext()) {
461: CategoryPlot plot = (CategoryPlot) iterator.next();
462: plot.setOrientation(orientation);
463: }
464:
465: }
466:
467:
472: public LegendItemCollection getLegendItems() {
473: LegendItemCollection result = getFixedLegendItems();
474: if (result == null) {
475: result = new LegendItemCollection();
476: if (this.subplots != null) {
477: Iterator iterator = this.subplots.iterator();
478: while (iterator.hasNext()) {
479: CategoryPlot plot = (CategoryPlot) iterator.next();
480: LegendItemCollection more = plot.getLegendItems();
481: result.addAll(more);
482: }
483: }
484: }
485: return result;
486: }
487:
488:
494: public List getCategories() {
495: List result = new java.util.ArrayList();
496: if (this.subplots != null) {
497: Iterator iterator = this.subplots.iterator();
498: while (iterator.hasNext()) {
499: CategoryPlot plot = (CategoryPlot) iterator.next();
500: List more = plot.getCategories();
501: Iterator moreIterator = more.iterator();
502: while (moreIterator.hasNext()) {
503: Comparable category = (Comparable) moreIterator.next();
504: if (!result.contains(category)) {
505: result.add(category);
506: }
507: }
508: }
509: }
510: return Collections.unmodifiableList(result);
511: }
512:
513:
522: public List getCategoriesForAxis(CategoryAxis axis) {
523:
524:
525: return getCategories();
526: }
527:
528:
536: public void handleClick(int x, int y, PlotRenderingInfo info) {
537:
538: Rectangle2D dataArea = info.getDataArea();
539: if (dataArea.contains(x, y)) {
540: for (int i = 0; i < this.subplots.size(); i++) {
541: CategoryPlot subplot = (CategoryPlot) this.subplots.get(i);
542: PlotRenderingInfo subplotInfo = info.getSubplotInfo(i);
543: subplot.handleClick(x, y, subplotInfo);
544: }
545: }
546:
547: }
548:
549:
555: public void plotChanged(PlotChangeEvent event) {
556: notifyListeners(event);
557: }
558:
559:
566: public boolean equals(Object obj) {
567: if (obj == this) {
568: return true;
569: }
570: if (!(obj instanceof CombinedDomainCategoryPlot)) {
571: return false;
572: }
573: if (!super.equals(obj)) {
574: return false;
575: }
576: CombinedDomainCategoryPlot plot = (CombinedDomainCategoryPlot) obj;
577: if (!ObjectUtilities.equal(this.subplots, plot.subplots)) {
578: return false;
579: }
580: if (this.totalWeight != plot.totalWeight) {
581: return false;
582: }
583: if (this.gap != plot.gap) {
584: return false;
585: }
586: return true;
587: }
588:
589:
597: public Object clone() throws CloneNotSupportedException {
598:
599: CombinedDomainCategoryPlot result
600: = (CombinedDomainCategoryPlot) super.clone();
601: result.subplots = (List) ObjectUtilities.deepClone(this.subplots);
602: for (Iterator it = result.subplots.iterator(); it.hasNext();) {
603: Plot child = (Plot) it.next();
604: child.setParent(result);
605: }
606: return result;
607:
608: }
609:
610: }