1:
55:
56: package ;
57:
58: import ;
59: import ;
60: import ;
61: import ;
62: import ;
63: import ;
64: import ;
65:
66: import ;
67: import ;
68: import ;
69: import ;
70: import ;
71: import ;
72: import ;
73: import ;
74: import ;
75: import ;
76:
77:
80: public class CombinedDomainCategoryPlot extends CategoryPlot
81: implements Zoomable,
82: Cloneable, PublicCloneable,
83: Serializable,
84: PlotChangeListener {
85:
86:
87: private static final long serialVersionUID = 8207194522653701572L;
88:
89:
90: private List subplots;
91:
92:
93: private int totalWeight;
94:
95:
96: private double gap;
97:
98:
99: private transient Rectangle2D[] subplotAreas;
100:
101:
102:
105: public CombinedDomainCategoryPlot() {
106: this(new CategoryAxis());
107: }
108:
109:
115: public CombinedDomainCategoryPlot(CategoryAxis domainAxis) {
116: super(null, domainAxis, null, 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: notifyListeners(new PlotChangeEvent(this));
140: }
141:
142:
148: public void add(CategoryPlot subplot) {
149: add(subplot, 1);
150: }
151:
152:
159: public void add(CategoryPlot subplot, int weight) {
160: if (subplot == null) {
161: throw new IllegalArgumentException("Null 'subplot' argument.");
162: }
163: if (weight < 1) {
164: throw new IllegalArgumentException("Require weight >= 1.");
165: }
166: subplot.setParent(this);
167: subplot.setWeight(weight);
168: subplot.setInsets(new RectangleInsets(0.0, 0.0, 0.0, 0.0));
169: subplot.setDomainAxis(null);
170: subplot.setOrientation(getOrientation());
171: subplot.addChangeListener(this);
172: this.subplots.add(subplot);
173: this.totalWeight += weight;
174: CategoryAxis axis = getDomainAxis();
175: if (axis != null) {
176: axis.configure();
177: }
178: notifyListeners(new PlotChangeEvent(this));
179: }
180:
181:
189: public void remove(CategoryPlot subplot) {
190: if (subplot == null) {
191: throw new IllegalArgumentException("Null 'subplot' argument.");
192: }
193: int position = -1;
194: int size = this.subplots.size();
195: int i = 0;
196: while (position == -1 && i < size) {
197: if (this.subplots.get(i) == subplot) {
198: position = i;
199: }
200: i++;
201: }
202: if (position != -1) {
203: this.subplots.remove(position);
204: subplot.setParent(null);
205: subplot.removeChangeListener(this);
206: this.totalWeight -= subplot.getWeight();
207:
208: CategoryAxis domain = getDomainAxis();
209: if (domain != null) {
210: domain.configure();
211: }
212: notifyListeners(new PlotChangeEvent(this));
213: }
214: }
215:
216:
221: public List getSubplots() {
222: return Collections.unmodifiableList(this.subplots);
223: }
224:
225:
234: public CategoryPlot findSubplot(PlotRenderingInfo info, Point2D source) {
235: CategoryPlot result = null;
236: int subplotIndex = info.getSubplotIndex(source);
237: if (subplotIndex >= 0) {
238: result = (CategoryPlot) this.subplots.get(subplotIndex);
239: }
240: return result;
241: }
242:
243:
250: public void zoomRangeAxes(double factor, PlotRenderingInfo info,
251: Point2D source) {
252: CategoryPlot subplot = findSubplot(info, source);
253: if (subplot != null) {
254: subplot.zoomRangeAxes(factor, info, source);
255: }
256: }
257:
258:
266: public void zoomRangeAxes(double lowerPercent, double upperPercent,
267: PlotRenderingInfo info, Point2D source) {
268: CategoryPlot subplot = findSubplot(info, source);
269: if (subplot != null) {
270: subplot.zoomRangeAxes(lowerPercent, upperPercent, info, source);
271: }
272: }
273:
274:
282: protected AxisSpace calculateAxisSpace(Graphics2D g2,
283: Rectangle2D plotArea) {
284:
285: AxisSpace space = new AxisSpace();
286: PlotOrientation orientation = getOrientation();
287:
288:
289: AxisSpace fixed = getFixedDomainAxisSpace();
290: if (fixed != null) {
291: if (orientation == PlotOrientation.HORIZONTAL) {
292: space.setLeft(fixed.getLeft());
293: space.setRight(fixed.getRight());
294: }
295: else if (orientation == PlotOrientation.VERTICAL) {
296: space.setTop(fixed.getTop());
297: space.setBottom(fixed.getBottom());
298: }
299: }
300: else {
301: CategoryAxis categoryAxis = getDomainAxis();
302: RectangleEdge categoryEdge = Plot.resolveDomainAxisLocation(
303: getDomainAxisLocation(), orientation
304: );
305: if (categoryAxis != null) {
306: space = categoryAxis.reserveSpace(
307: g2, this, plotArea, categoryEdge, space
308: );
309: }
310: else {
311: if (getDrawSharedDomainAxis()) {
312: space = getDomainAxis().reserveSpace(
313: g2, this, plotArea, categoryEdge, space
314: );
315: }
316: }
317: }
318:
319: Rectangle2D adjustedPlotArea = space.shrink(plotArea, null);
320:
321:
322: int n = this.subplots.size();
323: this.subplotAreas = new Rectangle2D[n];
324: double x = adjustedPlotArea.getX();
325: double y = adjustedPlotArea.getY();
326: double usableSize = 0.0;
327: if (orientation == PlotOrientation.HORIZONTAL) {
328: usableSize = adjustedPlotArea.getWidth() - this.gap * (n - 1);
329: }
330: else if (orientation == PlotOrientation.VERTICAL) {
331: usableSize = adjustedPlotArea.getHeight() - this.gap * (n - 1);
332: }
333:
334: for (int i = 0; i < n; i++) {
335: CategoryPlot plot = (CategoryPlot) this.subplots.get(i);
336:
337:
338: if (orientation == PlotOrientation.HORIZONTAL) {
339: double w = usableSize * plot.getWeight() / this.totalWeight;
340: this.subplotAreas[i] = new Rectangle2D.Double(
341: x, y, w, adjustedPlotArea.getHeight()
342: );
343: x = x + w + this.gap;
344: }
345: else if (orientation == PlotOrientation.VERTICAL) {
346: double h = usableSize * plot.getWeight() / this.totalWeight;
347: this.subplotAreas[i] = new Rectangle2D.Double(
348: x, y, adjustedPlotArea.getWidth(), h
349: );
350: y = y + h + this.gap;
351: }
352:
353: AxisSpace subSpace = plot.calculateRangeAxisSpace(
354: g2, this.subplotAreas[i], null
355: );
356: space.ensureAtLeast(subSpace);
357:
358: }
359:
360: return space;
361: }
362:
363:
376: public void draw(Graphics2D g2,
377: Rectangle2D area,
378: Point2D anchor,
379: PlotState parentState,
380: PlotRenderingInfo info) {
381:
382:
383: if (info != null) {
384: info.setPlotArea(area);
385: }
386:
387:
388: RectangleInsets insets = getInsets();
389: area.setRect(
390: area.getX() + insets.getLeft(),
391: area.getY() + insets.getTop(),
392: area.getWidth() - insets.getLeft() - insets.getRight(),
393: area.getHeight() - insets.getTop() - insets.getBottom()
394: );
395:
396:
397:
398: setFixedRangeAxisSpaceForSubplots(null);
399: AxisSpace space = calculateAxisSpace(g2, area);
400: Rectangle2D dataArea = space.shrink(area, null);
401:
402:
403: setFixedRangeAxisSpaceForSubplots(space);
404:
405:
406: CategoryAxis axis = getDomainAxis();
407: RectangleEdge domainEdge = getDomainAxisEdge();
408: double cursor = RectangleEdge.coordinate(dataArea, domainEdge);
409: AxisState axisState = axis.draw(
410: g2, cursor, area, dataArea, domainEdge, info
411: );
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:
496: List result = new java.util.ArrayList();
497:
498: if (this.subplots != null) {
499: Iterator iterator = this.subplots.iterator();
500: while (iterator.hasNext()) {
501: CategoryPlot plot = (CategoryPlot) iterator.next();
502: List more = plot.getCategories();
503: Iterator moreIterator = more.iterator();
504: while (moreIterator.hasNext()) {
505: Comparable category = (Comparable) moreIterator.next();
506: if (!result.contains(category)) {
507: result.add(category);
508: }
509: }
510: }
511: }
512:
513: return Collections.unmodifiableList(result);
514: }
515:
516:
524: public void handleClick(int x, int y, PlotRenderingInfo info) {
525:
526: Rectangle2D dataArea = info.getDataArea();
527: if (dataArea.contains(x, y)) {
528: for (int i = 0; i < this.subplots.size(); i++) {
529: CategoryPlot subplot = (CategoryPlot) this.subplots.get(i);
530: PlotRenderingInfo subplotInfo = info.getSubplotInfo(i);
531: subplot.handleClick(x, y, subplotInfo);
532: }
533: }
534:
535: }
536:
537:
543: public void plotChanged(PlotChangeEvent event) {
544: notifyListeners(event);
545: }
546:
547:
554: public boolean equals(Object obj) {
555: if (obj == this) {
556: return true;
557: }
558: if (!(obj instanceof CombinedDomainCategoryPlot)) {
559: return false;
560: }
561: if (!super.equals(obj)) {
562: return false;
563: }
564: CombinedDomainCategoryPlot plot = (CombinedDomainCategoryPlot) obj;
565: if (!ObjectUtilities.equal(this.subplots, plot.subplots)) {
566: return false;
567: }
568: if (this.totalWeight != plot.totalWeight) {
569: return false;
570: }
571: if (this.gap != plot.gap) {
572: return false;
573: }
574: return true;
575: }
576:
577:
585: public Object clone() throws CloneNotSupportedException {
586:
587: CombinedDomainCategoryPlot result
588: = (CombinedDomainCategoryPlot) super.clone();
589: result.subplots = (List) ObjectUtilities.deepClone(this.subplots);
590: for (Iterator it = result.subplots.iterator(); it.hasNext();) {
591: Plot child = (Plot) it.next();
592: child.setParent(result);
593: }
594: return result;
595:
596: }
597:
598: }