1:
48:
49: package ;
50:
51: import ;
52: import ;
53: import ;
54: import ;
55: import ;
56: import ;
57: import ;
58: import ;
59: import ;
60: import ;
61: import ;
62: import ;
63:
64: import ;
65: import ;
66: import ;
67: import ;
68: import ;
69: import ;
70: import ;
71: import ;
72: import ;
73:
74:
77: public class SubCategoryAxis extends CategoryAxis
78: implements Cloneable, Serializable {
79:
80:
81: private static final long serialVersionUID = -1279463299793228344L;
82:
83:
84: private List subCategories;
85:
86:
87: private Font subLabelFont = new Font("SansSerif", Font.PLAIN, 10);
88:
89:
90: private transient Paint subLabelPaint = Color.black;
91:
92:
97: public SubCategoryAxis(String label) {
98: super(label);
99: this.subCategories = new java.util.ArrayList();
100: }
101:
102:
108: public void addSubCategory(Comparable subCategory) {
109: if (subCategory == null) {
110: throw new IllegalArgumentException("Null 'subcategory' axis.");
111: }
112: this.subCategories.add(subCategory);
113: notifyListeners(new AxisChangeEvent(this));
114: }
115:
116:
123: public Font getSubLabelFont() {
124: return this.subLabelFont;
125: }
126:
127:
135: public void setSubLabelFont(Font font) {
136: if (font == null) {
137: throw new IllegalArgumentException("Null 'font' argument.");
138: }
139: this.subLabelFont = font;
140: notifyListeners(new AxisChangeEvent(this));
141: }
142:
143:
150: public Paint getSubLabelPaint() {
151: return this.subLabelPaint;
152: }
153:
154:
162: public void setSubLabelPaint(Paint paint) {
163: if (paint == null) {
164: throw new IllegalArgumentException("Null 'paint' argument.");
165: }
166: this.subLabelPaint = paint;
167: notifyListeners(new AxisChangeEvent(this));
168: }
169:
170:
181: public AxisSpace reserveSpace(Graphics2D g2, Plot plot,
182: Rectangle2D plotArea,
183: RectangleEdge edge, AxisSpace space) {
184:
185:
186: if (space == null) {
187: space = new AxisSpace();
188: }
189:
190:
191: if (!isVisible()) {
192: return space;
193: }
194:
195: space = super.reserveSpace(g2, plot, plotArea, edge, space);
196: double maxdim = getMaxDim(g2, edge);
197: if (RectangleEdge.isTopOrBottom(edge)) {
198: space.add(maxdim, edge);
199: }
200: else if (RectangleEdge.isLeftOrRight(edge)) {
201: space.add(maxdim, edge);
202: }
203: return space;
204: }
205:
206:
215: private double getMaxDim(Graphics2D g2, RectangleEdge edge) {
216: double result = 0.0;
217: g2.setFont(this.subLabelFont);
218: FontMetrics fm = g2.getFontMetrics();
219: Iterator iterator = this.subCategories.iterator();
220: while (iterator.hasNext()) {
221: Comparable subcategory = (Comparable) iterator.next();
222: String label = subcategory.toString();
223: Rectangle2D bounds = TextUtilities.getTextBounds(label, g2, fm);
224: double dim = 0.0;
225: if (RectangleEdge.isLeftOrRight(edge)) {
226: dim = bounds.getWidth();
227: }
228: else {
229: dim = bounds.getHeight();
230: }
231: result = Math.max(result, dim);
232: }
233: return result;
234: }
235:
236:
252: public AxisState draw(Graphics2D g2,
253: double cursor,
254: Rectangle2D plotArea,
255: Rectangle2D dataArea,
256: RectangleEdge edge,
257: PlotRenderingInfo plotState) {
258:
259:
260: if (!isVisible()) {
261: return new AxisState(cursor);
262: }
263:
264: if (isAxisLineVisible()) {
265: drawAxisLine(g2, cursor, dataArea, edge);
266: }
267:
268:
269: AxisState state = new AxisState(cursor);
270: state = drawSubCategoryLabels(
271: g2, plotArea, dataArea, edge, state, plotState
272: );
273: state = drawCategoryLabels(g2, plotArea, dataArea, edge, state,
274: plotState);
275: state = drawLabel(getLabel(), g2, plotArea, dataArea, edge, state);
276:
277: return state;
278:
279: }
280:
281:
295: protected AxisState drawSubCategoryLabels(Graphics2D g2,
296: Rectangle2D plotArea,
297: Rectangle2D dataArea,
298: RectangleEdge edge,
299: AxisState state,
300: PlotRenderingInfo plotState) {
301:
302: if (state == null) {
303: throw new IllegalArgumentException("Null 'state' argument.");
304: }
305:
306: g2.setFont(this.subLabelFont);
307: g2.setPaint(this.subLabelPaint);
308: CategoryPlot plot = (CategoryPlot) getPlot();
309: CategoryDataset dataset = plot.getDataset();
310: int categoryCount = dataset.getColumnCount();
311:
312: double maxdim = getMaxDim(g2, edge);
313: for (int categoryIndex = 0; categoryIndex < categoryCount;
314: categoryIndex++) {
315:
316: double x0 = 0.0;
317: double x1 = 0.0;
318: double y0 = 0.0;
319: double y1 = 0.0;
320: if (edge == RectangleEdge.TOP) {
321: x0 = getCategoryStart(categoryIndex, categoryCount, dataArea,
322: edge);
323: x1 = getCategoryEnd(categoryIndex, categoryCount, dataArea,
324: edge);
325: y1 = state.getCursor();
326: y0 = y1 - maxdim;
327: }
328: else if (edge == RectangleEdge.BOTTOM) {
329: x0 = getCategoryStart(categoryIndex, categoryCount, dataArea,
330: edge);
331: x1 = getCategoryEnd(categoryIndex, categoryCount, dataArea,
332: edge);
333: y0 = state.getCursor();
334: y1 = y0 + maxdim;
335: }
336: else if (edge == RectangleEdge.LEFT) {
337: y0 = getCategoryStart(categoryIndex, categoryCount, dataArea,
338: edge);
339: y1 = getCategoryEnd(categoryIndex, categoryCount, dataArea,
340: edge);
341: x1 = state.getCursor();
342: x0 = x1 - maxdim;
343: }
344: else if (edge == RectangleEdge.RIGHT) {
345: y0 = getCategoryStart(categoryIndex, categoryCount, dataArea,
346: edge);
347: y1 = getCategoryEnd(categoryIndex, categoryCount, dataArea,
348: edge);
349: x0 = state.getCursor();
350: x1 = x0 + maxdim;
351: }
352: Rectangle2D area = new Rectangle2D.Double(x0, y0, (x1 - x0),
353: (y1 - y0));
354: int subCategoryCount = this.subCategories.size();
355: float width = (float) ((x1 - x0) / subCategoryCount);
356: float height = (float) ((y1 - y0) / subCategoryCount);
357: float xx = 0.0f;
358: float yy = 0.0f;
359: for (int i = 0; i < subCategoryCount; i++) {
360: if (RectangleEdge.isTopOrBottom(edge)) {
361: xx = (float) (x0 + (i + 0.5) * width);
362: yy = (float) area.getCenterY();
363: }
364: else {
365: xx = (float) area.getCenterX();
366: yy = (float) (y0 + (i + 0.5) * height);
367: }
368: String label = this.subCategories.get(i).toString();
369: TextUtilities.drawRotatedString(label, g2, xx, yy,
370: TextAnchor.CENTER, 0.0, TextAnchor.CENTER);
371: }
372: }
373:
374: if (edge.equals(RectangleEdge.TOP)) {
375: double h = maxdim;
376: state.cursorUp(h);
377: }
378: else if (edge.equals(RectangleEdge.BOTTOM)) {
379: double h = maxdim;
380: state.cursorDown(h);
381: }
382: else if (edge == RectangleEdge.LEFT) {
383: double w = maxdim;
384: state.cursorLeft(w);
385: }
386: else if (edge == RectangleEdge.RIGHT) {
387: double w = maxdim;
388: state.cursorRight(w);
389: }
390: return state;
391: }
392:
393:
400: public boolean equals(Object obj) {
401: if (obj == this) {
402: return true;
403: }
404: if (obj instanceof SubCategoryAxis && super.equals(obj)) {
405: SubCategoryAxis axis = (SubCategoryAxis) obj;
406: if (!this.subCategories.equals(axis.subCategories)) {
407: return false;
408: }
409: if (!this.subLabelFont.equals(axis.subLabelFont)) {
410: return false;
411: }
412: if (!this.subLabelPaint.equals(axis.subLabelPaint)) {
413: return false;
414: }
415: return true;
416: }
417: return false;
418: }
419:
420:
427: private void writeObject(ObjectOutputStream stream) throws IOException {
428: stream.defaultWriteObject();
429: SerialUtilities.writePaint(this.subLabelPaint, stream);
430: }
431:
432:
440: private void readObject(ObjectInputStream stream)
441: throws IOException, ClassNotFoundException {
442: stream.defaultReadObject();
443: this.subLabelPaint = SerialUtilities.readPaint(stream);
444: }
445:
446: }