1:
57:
58: package ;
59:
60: import ;
61: import ;
62: import ;
63: import ;
64: import ;
65: import ;
66: import ;
67:
68: import ;
69: import ;
70: import ;
71: import ;
72: import ;
73: import ;
74: import ;
75: import ;
76: import ;
77: import ;
78:
79:
82: public class CombinedDomainCategoryPlot extends CategoryPlot
83: implements Zoomable,
84: Cloneable, PublicCloneable,
85: Serializable,
86: PlotChangeListener {
87:
88:
89: private static final long serialVersionUID = 8207194522653701572L;
90:
91:
92: private List subplots;
93:
94:
95: private int totalWeight;
96:
97:
98: private double gap;
99:
100:
101: private transient Rectangle2D[] subplotAreas;
102:
103:
104:
107: public CombinedDomainCategoryPlot() {
108: this(new CategoryAxis());
109: }
110:
111:
117: public CombinedDomainCategoryPlot(CategoryAxis domainAxis) {
118: super(null, domainAxis, null, null);
119: this.subplots = new java.util.ArrayList();
120: this.totalWeight = 0;
121: this.gap = 5.0;
122: }
123:
124:
129: public double getGap() {
130: return this.gap;
131: }
132:
133:
139: public void setGap(double gap) {
140: this.gap = gap;
141: notifyListeners(new PlotChangeEvent(this));
142: }
143:
144:
153: public void add(CategoryPlot subplot) {
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 < 1) {
172: throw new IllegalArgumentException("Require weight >= 1.");
173: }
174: subplot.setParent(this);
175: subplot.setWeight(weight);
176: subplot.setInsets(new RectangleInsets(0.0, 0.0, 0.0, 0.0));
177: subplot.setDomainAxis(null);
178: subplot.setOrientation(getOrientation());
179: subplot.addChangeListener(this);
180: this.subplots.add(subplot);
181: this.totalWeight += weight;
182: CategoryAxis axis = getDomainAxis();
183: if (axis != null) {
184: axis.configure();
185: }
186: notifyListeners(new PlotChangeEvent(this));
187: }
188:
189:
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: CategoryAxis domain = getDomainAxis();
217: if (domain != null) {
218: domain.configure();
219: }
220: notifyListeners(new PlotChangeEvent(this));
221: }
222: }
223:
224:
229: public List getSubplots() {
230: return Collections.unmodifiableList(this.subplots);
231: }
232:
233:
242: public CategoryPlot findSubplot(PlotRenderingInfo info, Point2D source) {
243: if (info == null) {
244: throw new IllegalArgumentException("Null 'info' argument.");
245: }
246: if (source == null) {
247: throw new IllegalArgumentException("Null 'source' argument.");
248: }
249: CategoryPlot result = null;
250: int subplotIndex = info.getSubplotIndex(source);
251: if (subplotIndex >= 0) {
252: result = (CategoryPlot) this.subplots.get(subplotIndex);
253: }
254: return result;
255: }
256:
257:
264: public void zoomRangeAxes(double factor, PlotRenderingInfo info,
265: Point2D source) {
266:
267: CategoryPlot subplot = findSubplot(info, source);
268: if (subplot != null) {
269: subplot.zoomRangeAxes(factor, info, source);
270: }
271: else {
272:
273:
274: Iterator iterator = getSubplots().iterator();
275: while (iterator.hasNext()) {
276: subplot = (CategoryPlot) iterator.next();
277: subplot.zoomRangeAxes(factor, info, source);
278: }
279: }
280: }
281:
282:
290: public void zoomRangeAxes(double lowerPercent, double upperPercent,
291: PlotRenderingInfo info, Point2D source) {
292:
293: CategoryPlot subplot = findSubplot(info, source);
294: if (subplot != null) {
295: subplot.zoomRangeAxes(lowerPercent, upperPercent, info, source);
296: }
297: else {
298:
299:
300: Iterator iterator = getSubplots().iterator();
301: while (iterator.hasNext()) {
302: subplot = (CategoryPlot) iterator.next();
303: subplot.zoomRangeAxes(lowerPercent, upperPercent, info, source);
304: }
305: }
306: }
307:
308:
316: protected AxisSpace calculateAxisSpace(Graphics2D g2,
317: Rectangle2D plotArea) {
318:
319: AxisSpace space = new AxisSpace();
320: PlotOrientation orientation = getOrientation();
321:
322:
323: AxisSpace fixed = getFixedDomainAxisSpace();
324: if (fixed != null) {
325: if (orientation == PlotOrientation.HORIZONTAL) {
326: space.setLeft(fixed.getLeft());
327: space.setRight(fixed.getRight());
328: }
329: else if (orientation == PlotOrientation.VERTICAL) {
330: space.setTop(fixed.getTop());
331: space.setBottom(fixed.getBottom());
332: }
333: }
334: else {
335: CategoryAxis categoryAxis = getDomainAxis();
336: RectangleEdge categoryEdge = Plot.resolveDomainAxisLocation(
337: getDomainAxisLocation(), orientation);
338: if (categoryAxis != null) {
339: space = categoryAxis.reserveSpace(g2, this, plotArea,
340: categoryEdge, space);
341: }
342: else {
343: if (getDrawSharedDomainAxis()) {
344: space = getDomainAxis().reserveSpace(g2, this, plotArea,
345: categoryEdge, space);
346: }
347: }
348: }
349:
350: Rectangle2D adjustedPlotArea = space.shrink(plotArea, null);
351:
352:
353: int n = this.subplots.size();
354: this.subplotAreas = new Rectangle2D[n];
355: double x = adjustedPlotArea.getX();
356: double y = adjustedPlotArea.getY();
357: double usableSize = 0.0;
358: if (orientation == PlotOrientation.HORIZONTAL) {
359: usableSize = adjustedPlotArea.getWidth() - this.gap * (n - 1);
360: }
361: else if (orientation == PlotOrientation.VERTICAL) {
362: usableSize = adjustedPlotArea.getHeight() - this.gap * (n - 1);
363: }
364:
365: for (int i = 0; i < n; i++) {
366: CategoryPlot plot = (CategoryPlot) this.subplots.get(i);
367:
368:
369: if (orientation == PlotOrientation.HORIZONTAL) {
370: double w = usableSize * plot.getWeight() / this.totalWeight;
371: this.subplotAreas[i] = new Rectangle2D.Double(x, y, w,
372: adjustedPlotArea.getHeight());
373: x = x + w + this.gap;
374: }
375: else if (orientation == PlotOrientation.VERTICAL) {
376: double h = usableSize * plot.getWeight() / this.totalWeight;
377: this.subplotAreas[i] = new Rectangle2D.Double(x, y,
378: adjustedPlotArea.getWidth(), h);
379: y = y + h + this.gap;
380: }
381:
382: AxisSpace subSpace = plot.calculateRangeAxisSpace(g2,
383: this.subplotAreas[i], null);
384: space.ensureAtLeast(subSpace);
385:
386: }
387:
388: return space;
389: }
390:
391:
404: public void draw(Graphics2D g2,
405: Rectangle2D area,
406: Point2D anchor,
407: PlotState parentState,
408: PlotRenderingInfo info) {
409:
410:
411: if (info != null) {
412: info.setPlotArea(area);
413: }
414:
415:
416: RectangleInsets insets = getInsets();
417: area.setRect(area.getX() + insets.getLeft(),
418: area.getY() + insets.getTop(),
419: area.getWidth() - insets.getLeft() - insets.getRight(),
420: area.getHeight() - insets.getTop() - insets.getBottom());
421:
422:
423:
424: setFixedRangeAxisSpaceForSubplots(null);
425: AxisSpace space = calculateAxisSpace(g2, area);
426: Rectangle2D dataArea = space.shrink(area, null);
427:
428:
429: setFixedRangeAxisSpaceForSubplots(space);
430:
431:
432: CategoryAxis axis = getDomainAxis();
433: RectangleEdge domainEdge = getDomainAxisEdge();
434: double cursor = RectangleEdge.coordinate(dataArea, domainEdge);
435: AxisState axisState = axis.draw(g2, cursor, area, dataArea,
436: domainEdge, info);
437: if (parentState == null) {
438: parentState = new PlotState();
439: }
440: parentState.getSharedAxisStates().put(axis, axisState);
441:
442:
443: for (int i = 0; i < this.subplots.size(); i++) {
444: CategoryPlot plot = (CategoryPlot) this.subplots.get(i);
445: PlotRenderingInfo subplotInfo = null;
446: if (info != null) {
447: subplotInfo = new PlotRenderingInfo(info.getOwner());
448: info.addSubplotInfo(subplotInfo);
449: }
450: plot.draw(g2, this.subplotAreas[i], null, parentState, subplotInfo);
451: }
452:
453: if (info != null) {
454: info.setDataArea(dataArea);
455: }
456:
457: }
458:
459:
465: protected void setFixedRangeAxisSpaceForSubplots(AxisSpace space) {
466: Iterator iterator = this.subplots.iterator();
467: while (iterator.hasNext()) {
468: CategoryPlot plot = (CategoryPlot) iterator.next();
469: plot.setFixedRangeAxisSpace(space, false);
470: }
471: }
472:
473:
478: public void setOrientation(PlotOrientation orientation) {
479:
480: super.setOrientation(orientation);
481:
482: Iterator iterator = this.subplots.iterator();
483: while (iterator.hasNext()) {
484: CategoryPlot plot = (CategoryPlot) iterator.next();
485: plot.setOrientation(orientation);
486: }
487:
488: }
489:
490:
495: public LegendItemCollection getLegendItems() {
496: LegendItemCollection result = getFixedLegendItems();
497: if (result == null) {
498: result = new LegendItemCollection();
499: if (this.subplots != null) {
500: Iterator iterator = this.subplots.iterator();
501: while (iterator.hasNext()) {
502: CategoryPlot plot = (CategoryPlot) iterator.next();
503: LegendItemCollection more = plot.getLegendItems();
504: result.addAll(more);
505: }
506: }
507: }
508: return result;
509: }
510:
511:
517: public List getCategories() {
518: List result = new java.util.ArrayList();
519: if (this.subplots != null) {
520: Iterator iterator = this.subplots.iterator();
521: while (iterator.hasNext()) {
522: CategoryPlot plot = (CategoryPlot) iterator.next();
523: List more = plot.getCategories();
524: Iterator moreIterator = more.iterator();
525: while (moreIterator.hasNext()) {
526: Comparable category = (Comparable) moreIterator.next();
527: if (!result.contains(category)) {
528: result.add(category);
529: }
530: }
531: }
532: }
533: return Collections.unmodifiableList(result);
534: }
535:
536:
545: public List getCategoriesForAxis(CategoryAxis axis) {
546:
547:
548: return getCategories();
549: }
550:
551:
559: public void handleClick(int x, int y, PlotRenderingInfo info) {
560:
561: Rectangle2D dataArea = info.getDataArea();
562: if (dataArea.contains(x, y)) {
563: for (int i = 0; i < this.subplots.size(); i++) {
564: CategoryPlot subplot = (CategoryPlot) this.subplots.get(i);
565: PlotRenderingInfo subplotInfo = info.getSubplotInfo(i);
566: subplot.handleClick(x, y, subplotInfo);
567: }
568: }
569:
570: }
571:
572:
578: public void plotChanged(PlotChangeEvent event) {
579: notifyListeners(event);
580: }
581:
582:
589: public boolean equals(Object obj) {
590: if (obj == this) {
591: return true;
592: }
593: if (!(obj instanceof CombinedDomainCategoryPlot)) {
594: return false;
595: }
596: if (!super.equals(obj)) {
597: return false;
598: }
599: CombinedDomainCategoryPlot plot = (CombinedDomainCategoryPlot) obj;
600: if (!ObjectUtilities.equal(this.subplots, plot.subplots)) {
601: return false;
602: }
603: if (this.totalWeight != plot.totalWeight) {
604: return false;
605: }
606: if (this.gap != plot.gap) {
607: return false;
608: }
609: return true;
610: }
611:
612:
620: public Object clone() throws CloneNotSupportedException {
621:
622: CombinedDomainCategoryPlot result
623: = (CombinedDomainCategoryPlot) super.clone();
624: result.subplots = (List) ObjectUtilities.deepClone(this.subplots);
625: for (Iterator it = result.subplots.iterator(); it.hasNext();) {
626: Plot child = (Plot) it.next();
627: child.setParent(result);
628: }
629: return result;
630:
631: }
632:
633: }