1:
62:
63: package ;
64:
65: import ;
66: import ;
67: import ;
68: import ;
69: import ;
70: import ;
71:
72: import ;
73: import ;
74: import ;
75: import ;
76: import ;
77: import ;
78: import ;
79: import ;
80: import ;
81: import ;
82: import ;
83:
84:
87: public class CombinedDomainCategoryPlot extends CategoryPlot
88: implements PlotChangeListener {
89:
90:
91: private static final long serialVersionUID = 8207194522653701572L;
92:
93:
94: private List subplots;
95:
96:
97: private int totalWeight;
98:
99:
100: private double gap;
101:
102:
103: private transient Rectangle2D[] subplotAreas;
104:
105:
106:
109: public CombinedDomainCategoryPlot() {
110: this(new CategoryAxis());
111: }
112:
113:
119: public CombinedDomainCategoryPlot(CategoryAxis domainAxis) {
120: super(null, domainAxis, null, null);
121: this.subplots = new java.util.ArrayList();
122: this.totalWeight = 0;
123: this.gap = 5.0;
124: }
125:
126:
131: public double getGap() {
132: return this.gap;
133: }
134:
135:
141: public void setGap(double gap) {
142: this.gap = gap;
143: fireChangeEvent();
144: }
145:
146:
155: public void add(CategoryPlot subplot) {
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 < 1) {
174: throw new IllegalArgumentException("Require weight >= 1.");
175: }
176: subplot.setParent(this);
177: subplot.setWeight(weight);
178: subplot.setInsets(new RectangleInsets(0.0, 0.0, 0.0, 0.0));
179: subplot.setDomainAxis(null);
180: subplot.setOrientation(getOrientation());
181: subplot.addChangeListener(this);
182: this.subplots.add(subplot);
183: this.totalWeight += weight;
184: CategoryAxis axis = getDomainAxis();
185: if (axis != null) {
186: axis.configure();
187: }
188: fireChangeEvent();
189: }
190:
191:
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: CategoryAxis domain = getDomainAxis();
219: if (domain != null) {
220: domain.configure();
221: }
222: fireChangeEvent();
223: }
224: }
225:
226:
232: public List getSubplots() {
233: if (this.subplots != null) {
234: return Collections.unmodifiableList(this.subplots);
235: }
236: else {
237: return Collections.EMPTY_LIST;
238: }
239: }
240:
241:
250: public CategoryPlot findSubplot(PlotRenderingInfo info, Point2D source) {
251: if (info == null) {
252: throw new IllegalArgumentException("Null 'info' argument.");
253: }
254: if (source == null) {
255: throw new IllegalArgumentException("Null 'source' argument.");
256: }
257: CategoryPlot result = null;
258: int subplotIndex = info.getSubplotIndex(source);
259: if (subplotIndex >= 0) {
260: result = (CategoryPlot) this.subplots.get(subplotIndex);
261: }
262: return result;
263: }
264:
265:
272: public void zoomRangeAxes(double factor, PlotRenderingInfo info,
273: Point2D source) {
274: zoomRangeAxes(factor, info, source, false);
275: }
276:
277:
285: public void zoomRangeAxes(double factor, PlotRenderingInfo info,
286: Point2D source, boolean useAnchor) {
287:
288: CategoryPlot subplot = findSubplot(info, source);
289: if (subplot != null) {
290: subplot.zoomRangeAxes(factor, info, source, useAnchor);
291: }
292: else {
293:
294:
295: Iterator iterator = getSubplots().iterator();
296: while (iterator.hasNext()) {
297: subplot = (CategoryPlot) iterator.next();
298: subplot.zoomRangeAxes(factor, info, source, useAnchor);
299: }
300: }
301: }
302:
303:
311: public void zoomRangeAxes(double lowerPercent, double upperPercent,
312: PlotRenderingInfo info, Point2D source) {
313:
314: CategoryPlot subplot = findSubplot(info, source);
315: if (subplot != null) {
316: subplot.zoomRangeAxes(lowerPercent, upperPercent, info, source);
317: }
318: else {
319:
320:
321: Iterator iterator = getSubplots().iterator();
322: while (iterator.hasNext()) {
323: subplot = (CategoryPlot) iterator.next();
324: subplot.zoomRangeAxes(lowerPercent, upperPercent, info, source);
325: }
326: }
327: }
328:
329:
337: protected AxisSpace calculateAxisSpace(Graphics2D g2,
338: Rectangle2D plotArea) {
339:
340: AxisSpace space = new AxisSpace();
341: PlotOrientation orientation = getOrientation();
342:
343:
344: AxisSpace fixed = getFixedDomainAxisSpace();
345: if (fixed != null) {
346: if (orientation == PlotOrientation.HORIZONTAL) {
347: space.setLeft(fixed.getLeft());
348: space.setRight(fixed.getRight());
349: }
350: else if (orientation == PlotOrientation.VERTICAL) {
351: space.setTop(fixed.getTop());
352: space.setBottom(fixed.getBottom());
353: }
354: }
355: else {
356: CategoryAxis categoryAxis = getDomainAxis();
357: RectangleEdge categoryEdge = Plot.resolveDomainAxisLocation(
358: getDomainAxisLocation(), orientation);
359: if (categoryAxis != null) {
360: space = categoryAxis.reserveSpace(g2, this, plotArea,
361: categoryEdge, space);
362: }
363: else {
364: if (getDrawSharedDomainAxis()) {
365: space = getDomainAxis().reserveSpace(g2, this, plotArea,
366: categoryEdge, space);
367: }
368: }
369: }
370:
371: Rectangle2D adjustedPlotArea = space.shrink(plotArea, null);
372:
373:
374: int n = this.subplots.size();
375: this.subplotAreas = new Rectangle2D[n];
376: double x = adjustedPlotArea.getX();
377: double y = adjustedPlotArea.getY();
378: double usableSize = 0.0;
379: if (orientation == PlotOrientation.HORIZONTAL) {
380: usableSize = adjustedPlotArea.getWidth() - this.gap * (n - 1);
381: }
382: else if (orientation == PlotOrientation.VERTICAL) {
383: usableSize = adjustedPlotArea.getHeight() - this.gap * (n - 1);
384: }
385:
386: for (int i = 0; i < n; i++) {
387: CategoryPlot plot = (CategoryPlot) this.subplots.get(i);
388:
389:
390: if (orientation == PlotOrientation.HORIZONTAL) {
391: double w = usableSize * plot.getWeight() / this.totalWeight;
392: this.subplotAreas[i] = new Rectangle2D.Double(x, y, w,
393: adjustedPlotArea.getHeight());
394: x = x + w + this.gap;
395: }
396: else if (orientation == PlotOrientation.VERTICAL) {
397: double h = usableSize * plot.getWeight() / this.totalWeight;
398: this.subplotAreas[i] = new Rectangle2D.Double(x, y,
399: adjustedPlotArea.getWidth(), h);
400: y = y + h + this.gap;
401: }
402:
403: AxisSpace subSpace = plot.calculateRangeAxisSpace(g2,
404: this.subplotAreas[i], null);
405: space.ensureAtLeast(subSpace);
406:
407: }
408:
409: return space;
410: }
411:
412:
425: public void draw(Graphics2D g2,
426: Rectangle2D area,
427: Point2D anchor,
428: PlotState parentState,
429: PlotRenderingInfo info) {
430:
431:
432: if (info != null) {
433: info.setPlotArea(area);
434: }
435:
436:
437: RectangleInsets insets = getInsets();
438: area.setRect(area.getX() + insets.getLeft(),
439: area.getY() + insets.getTop(),
440: area.getWidth() - insets.getLeft() - insets.getRight(),
441: area.getHeight() - insets.getTop() - insets.getBottom());
442:
443:
444:
445: setFixedRangeAxisSpaceForSubplots(null);
446: AxisSpace space = calculateAxisSpace(g2, area);
447: Rectangle2D dataArea = space.shrink(area, null);
448:
449:
450: setFixedRangeAxisSpaceForSubplots(space);
451:
452:
453: CategoryAxis axis = getDomainAxis();
454: RectangleEdge domainEdge = getDomainAxisEdge();
455: double cursor = RectangleEdge.coordinate(dataArea, domainEdge);
456: AxisState axisState = axis.draw(g2, cursor, area, dataArea,
457: domainEdge, info);
458: if (parentState == null) {
459: parentState = new PlotState();
460: }
461: parentState.getSharedAxisStates().put(axis, axisState);
462:
463:
464: for (int i = 0; i < this.subplots.size(); i++) {
465: CategoryPlot plot = (CategoryPlot) this.subplots.get(i);
466: PlotRenderingInfo subplotInfo = null;
467: if (info != null) {
468: subplotInfo = new PlotRenderingInfo(info.getOwner());
469: info.addSubplotInfo(subplotInfo);
470: }
471: plot.draw(g2, this.subplotAreas[i], null, parentState, subplotInfo);
472: }
473:
474: if (info != null) {
475: info.setDataArea(dataArea);
476: }
477:
478: }
479:
480:
486: protected void setFixedRangeAxisSpaceForSubplots(AxisSpace space) {
487: Iterator iterator = this.subplots.iterator();
488: while (iterator.hasNext()) {
489: CategoryPlot plot = (CategoryPlot) iterator.next();
490: plot.setFixedRangeAxisSpace(space, false);
491: }
492: }
493:
494:
499: public void setOrientation(PlotOrientation orientation) {
500:
501: super.setOrientation(orientation);
502:
503: Iterator iterator = this.subplots.iterator();
504: while (iterator.hasNext()) {
505: CategoryPlot plot = (CategoryPlot) iterator.next();
506: plot.setOrientation(orientation);
507: }
508:
509: }
510:
511:
525: public Range getDataRange(ValueAxis axis) {
526:
527: return super.getDataRange(axis);
528: }
529:
530:
535: public LegendItemCollection getLegendItems() {
536: LegendItemCollection result = getFixedLegendItems();
537: if (result == null) {
538: result = new LegendItemCollection();
539: if (this.subplots != null) {
540: Iterator iterator = this.subplots.iterator();
541: while (iterator.hasNext()) {
542: CategoryPlot plot = (CategoryPlot) iterator.next();
543: LegendItemCollection more = plot.getLegendItems();
544: result.addAll(more);
545: }
546: }
547: }
548: return result;
549: }
550:
551:
557: public List getCategories() {
558: List result = new java.util.ArrayList();
559: if (this.subplots != null) {
560: Iterator iterator = this.subplots.iterator();
561: while (iterator.hasNext()) {
562: CategoryPlot plot = (CategoryPlot) iterator.next();
563: List more = plot.getCategories();
564: Iterator moreIterator = more.iterator();
565: while (moreIterator.hasNext()) {
566: Comparable category = (Comparable) moreIterator.next();
567: if (!result.contains(category)) {
568: result.add(category);
569: }
570: }
571: }
572: }
573: return Collections.unmodifiableList(result);
574: }
575:
576:
585: public List getCategoriesForAxis(CategoryAxis axis) {
586:
587:
588: return getCategories();
589: }
590:
591:
599: public void handleClick(int x, int y, PlotRenderingInfo info) {
600:
601: Rectangle2D dataArea = info.getDataArea();
602: if (dataArea.contains(x, y)) {
603: for (int i = 0; i < this.subplots.size(); i++) {
604: CategoryPlot subplot = (CategoryPlot) this.subplots.get(i);
605: PlotRenderingInfo subplotInfo = info.getSubplotInfo(i);
606: subplot.handleClick(x, y, subplotInfo);
607: }
608: }
609:
610: }
611:
612:
618: public void plotChanged(PlotChangeEvent event) {
619: notifyListeners(event);
620: }
621:
622:
629: public boolean equals(Object obj) {
630: if (obj == this) {
631: return true;
632: }
633: if (!(obj instanceof CombinedDomainCategoryPlot)) {
634: return false;
635: }
636: if (!super.equals(obj)) {
637: return false;
638: }
639: CombinedDomainCategoryPlot plot = (CombinedDomainCategoryPlot) obj;
640: if (!ObjectUtilities.equal(this.subplots, plot.subplots)) {
641: return false;
642: }
643: if (this.totalWeight != plot.totalWeight) {
644: return false;
645: }
646: if (this.gap != plot.gap) {
647: return false;
648: }
649: return true;
650: }
651:
652:
660: public Object clone() throws CloneNotSupportedException {
661:
662: CombinedDomainCategoryPlot result
663: = (CombinedDomainCategoryPlot) super.clone();
664: result.subplots = (List) ObjectUtilities.deepClone(this.subplots);
665: for (Iterator it = result.subplots.iterator(); it.hasNext();) {
666: Plot child = (Plot) it.next();
667: child.setParent(result);
668: }
669: return result;
670:
671: }
672:
673: }