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:
107: public void addSubCategory(Comparable subCategory) {
108: this.subCategories.add(subCategory);
109: }
110:
111:
116: public Font getSubLabelFont() {
117: return this.subLabelFont;
118: }
119:
120:
126: public void setSubLabelFont(Font font) {
127: if (font == null) {
128: throw new IllegalArgumentException("Null 'font' argument.");
129: }
130: this.subLabelFont = font;
131: notifyListeners(new AxisChangeEvent(this));
132: }
133:
134:
139: public Paint getSubLabelPaint() {
140: return this.subLabelPaint;
141: }
142:
143:
149: public void setSubLabelPaint(Paint paint) {
150: if (paint == null) {
151: throw new IllegalArgumentException("Null 'paint' argument.");
152: }
153: this.subLabelPaint = paint;
154: notifyListeners(new AxisChangeEvent(this));
155: }
156:
157:
168: public AxisSpace reserveSpace(Graphics2D g2, Plot plot,
169: Rectangle2D plotArea,
170: RectangleEdge edge, AxisSpace space) {
171:
172:
173: if (space == null) {
174: space = new AxisSpace();
175: }
176:
177:
178: if (!isVisible()) {
179: return space;
180: }
181:
182: space = super.reserveSpace(g2, plot, plotArea, edge, space);
183: double maxdim = getMaxDim(g2, edge);
184: if (RectangleEdge.isTopOrBottom(edge)) {
185: space.add(maxdim, edge);
186: }
187: else if (RectangleEdge.isLeftOrRight(edge)) {
188: space.add(maxdim, edge);
189: }
190: return space;
191: }
192:
193:
202: private double getMaxDim(Graphics2D g2, RectangleEdge edge) {
203: double result = 0.0;
204: g2.setFont(this.subLabelFont);
205: FontMetrics fm = g2.getFontMetrics();
206: Iterator iterator = this.subCategories.iterator();
207: while (iterator.hasNext()) {
208: Comparable subcategory = (Comparable) iterator.next();
209: String label = subcategory.toString();
210: Rectangle2D bounds = TextUtilities.getTextBounds(label, g2, fm);
211: double dim = 0.0;
212: if (RectangleEdge.isLeftOrRight(edge)) {
213: dim = bounds.getWidth();
214: }
215: else {
216: dim = bounds.getHeight();
217: }
218: result = Math.max(result, dim);
219: }
220: return result;
221: }
222:
223:
239: public AxisState draw(Graphics2D g2,
240: double cursor,
241: Rectangle2D plotArea,
242: Rectangle2D dataArea,
243: RectangleEdge edge,
244: PlotRenderingInfo plotState) {
245:
246:
247: if (!isVisible()) {
248: return new AxisState(cursor);
249: }
250:
251: if (isAxisLineVisible()) {
252: drawAxisLine(g2, cursor, dataArea, edge);
253: }
254:
255:
256: AxisState state = new AxisState(cursor);
257: state = drawSubCategoryLabels(
258: g2, plotArea, dataArea, edge, state, plotState
259: );
260: state = drawCategoryLabels(g2, plotArea, dataArea, edge, state,
261: plotState);
262: state = drawLabel(getLabel(), g2, plotArea, dataArea, edge, state);
263:
264: return state;
265:
266: }
267:
268:
282: protected AxisState drawSubCategoryLabels(Graphics2D g2,
283: Rectangle2D plotArea,
284: Rectangle2D dataArea,
285: RectangleEdge edge,
286: AxisState state,
287: PlotRenderingInfo plotState) {
288:
289: if (state == null) {
290: throw new IllegalArgumentException("Null 'state' argument.");
291: }
292:
293: g2.setFont(this.subLabelFont);
294: g2.setPaint(this.subLabelPaint);
295: CategoryPlot plot = (CategoryPlot) getPlot();
296: CategoryDataset dataset = plot.getDataset();
297: int categoryCount = dataset.getColumnCount();
298:
299: double maxdim = getMaxDim(g2, edge);
300: for (int categoryIndex = 0; categoryIndex < categoryCount;
301: categoryIndex++) {
302:
303: double x0 = 0.0;
304: double x1 = 0.0;
305: double y0 = 0.0;
306: double y1 = 0.0;
307: if (edge == RectangleEdge.TOP) {
308: x0 = getCategoryStart(categoryIndex, categoryCount, dataArea,
309: edge);
310: x1 = getCategoryEnd(categoryIndex, categoryCount, dataArea,
311: edge);
312: y1 = state.getCursor();
313: y0 = y1 - maxdim;
314: }
315: else if (edge == RectangleEdge.BOTTOM) {
316: x0 = getCategoryStart(categoryIndex, categoryCount, dataArea,
317: edge);
318: x1 = getCategoryEnd(categoryIndex, categoryCount, dataArea,
319: edge);
320: y0 = state.getCursor();
321: y1 = y0 + maxdim;
322: }
323: else if (edge == RectangleEdge.LEFT) {
324: y0 = getCategoryStart(categoryIndex, categoryCount, dataArea,
325: edge);
326: y1 = getCategoryEnd(categoryIndex, categoryCount, dataArea,
327: edge);
328: x1 = state.getCursor();
329: x0 = x1 - maxdim;
330: }
331: else if (edge == RectangleEdge.RIGHT) {
332: y0 = getCategoryStart(categoryIndex, categoryCount, dataArea,
333: edge);
334: y1 = getCategoryEnd(categoryIndex, categoryCount, dataArea,
335: edge);
336: x0 = state.getCursor();
337: x1 = x0 + maxdim;
338: }
339: Rectangle2D area = new Rectangle2D.Double(x0, y0, (x1 - x0),
340: (y1 - y0));
341: int subCategoryCount = this.subCategories.size();
342: float width = (float) ((x1 - x0) / subCategoryCount);
343: float height = (float) ((y1 - y0) / subCategoryCount);
344: float xx = 0.0f;
345: float yy = 0.0f;
346: for (int i = 0; i < subCategoryCount; i++) {
347: if (RectangleEdge.isTopOrBottom(edge)) {
348: xx = (float) (x0 + (i + 0.5) * width);
349: yy = (float) area.getCenterY();
350: }
351: else {
352: xx = (float) area.getCenterX();
353: yy = (float) (y0 + (i + 0.5) * height);
354: }
355: String label = this.subCategories.get(i).toString();
356: TextUtilities.drawRotatedString(label, g2, xx, yy,
357: TextAnchor.CENTER, 0.0, TextAnchor.CENTER);
358: }
359: }
360:
361: if (edge.equals(RectangleEdge.TOP)) {
362: double h = maxdim;
363: state.cursorUp(h);
364: }
365: else if (edge.equals(RectangleEdge.BOTTOM)) {
366: double h = maxdim;
367: state.cursorDown(h);
368: }
369: else if (edge == RectangleEdge.LEFT) {
370: double w = maxdim;
371: state.cursorLeft(w);
372: }
373: else if (edge == RectangleEdge.RIGHT) {
374: double w = maxdim;
375: state.cursorRight(w);
376: }
377: return state;
378: }
379:
380:
387: public boolean equals(Object obj) {
388: if (obj == this) {
389: return true;
390: }
391: if (obj instanceof SubCategoryAxis && super.equals(obj)) {
392: SubCategoryAxis axis = (SubCategoryAxis) obj;
393: if (!this.subCategories.equals(axis.subCategories)) {
394: return false;
395: }
396: if (!this.subLabelFont.equals(axis.subLabelFont)) {
397: return false;
398: }
399: if (!this.subLabelPaint.equals(axis.subLabelPaint)) {
400: return false;
401: }
402: return true;
403: }
404: return false;
405: }
406:
407:
414: private void writeObject(ObjectOutputStream stream) throws IOException {
415: stream.defaultWriteObject();
416: SerialUtilities.writePaint(this.subLabelPaint, stream);
417: }
418:
419:
427: private void readObject(ObjectInputStream stream)
428: throws IOException, ClassNotFoundException {
429: stream.defaultReadObject();
430: this.subLabelPaint = SerialUtilities.readPaint(stream);
431: }
432:
433: }