001 /* ===========================================================
002 * JFreeChart : a free chart library for the Java(tm) platform
003 * ===========================================================
004 *
005 * (C) Copyright 2000-2007, by Object Refinery Limited and Contributors.
006 *
007 * Project Info: http://www.jfree.org/jfreechart/index.html
008 *
009 * This library is free software; you can redistribute it and/or modify it
010 * under the terms of the GNU Lesser General Public License as published by
011 * the Free Software Foundation; either version 2.1 of the License, or
012 * (at your option) any later version.
013 *
014 * This library is distributed in the hope that it will be useful, but
015 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
016 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
017 * License for more details.
018 *
019 * You should have received a copy of the GNU Lesser General Public
020 * License along with this library; if not, write to the Free Software
021 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
022 * USA.
023 *
024 * [Java is a trademark or registered trademark of Sun Microsystems, Inc.
025 * in the United States and other countries.]
026 *
027 * ---------------------------
028 * CategoryLabelPositions.java
029 * ---------------------------
030 * (C) Copyright 2004-2007, by Object Refinery Limited and Contributors.
031 *
032 * Original Author: David Gilbert (for Object Refinery Limited);
033 * Contributor(s): -;
034 *
035 * Changes
036 * -------
037 * 06-Jan-2004 : Version 1 (DG);
038 * 17-Feb-2004 : Added equals() method (DG);
039 * 05-Nov-2004 : Adjusted settings for UP_90 and DOWN_90 (DG);
040 *
041 */
042
043 package org.jfree.chart.axis;
044
045 import java.io.Serializable;
046
047 import org.jfree.text.TextBlockAnchor;
048 import org.jfree.ui.RectangleAnchor;
049 import org.jfree.ui.RectangleEdge;
050 import org.jfree.ui.TextAnchor;
051
052 /**
053 * Records the label positions for a category axis. Instances of this class
054 * are immutable.
055 */
056 public class CategoryLabelPositions implements Serializable {
057
058 /** For serialization. */
059 private static final long serialVersionUID = -8999557901920364580L;
060
061 /** STANDARD category label positions. */
062 public static final CategoryLabelPositions
063 STANDARD = new CategoryLabelPositions(
064 new CategoryLabelPosition(
065 RectangleAnchor.BOTTOM, TextBlockAnchor.BOTTOM_CENTER
066 ), // TOP
067 new CategoryLabelPosition(
068 RectangleAnchor.TOP, TextBlockAnchor.TOP_CENTER
069 ), // BOTTOM
070 new CategoryLabelPosition(
071 RectangleAnchor.RIGHT, TextBlockAnchor.CENTER_RIGHT,
072 CategoryLabelWidthType.RANGE, 0.30f
073 ), // LEFT
074 new CategoryLabelPosition(
075 RectangleAnchor.LEFT, TextBlockAnchor.CENTER_LEFT,
076 CategoryLabelWidthType.RANGE, 0.30f
077 ) // RIGHT
078 );
079
080 /** UP_90 category label positions. */
081 public static final CategoryLabelPositions
082 UP_90 = new CategoryLabelPositions(
083 new CategoryLabelPosition(
084 RectangleAnchor.BOTTOM, TextBlockAnchor.CENTER_LEFT,
085 TextAnchor.CENTER_LEFT, -Math.PI / 2.0,
086 CategoryLabelWidthType.RANGE, 0.30f
087 ), // TOP
088 new CategoryLabelPosition(
089 RectangleAnchor.TOP, TextBlockAnchor.CENTER_RIGHT,
090 TextAnchor.CENTER_RIGHT, -Math.PI / 2.0,
091 CategoryLabelWidthType.RANGE, 0.30f
092 ), // BOTTOM
093 new CategoryLabelPosition(
094 RectangleAnchor.RIGHT, TextBlockAnchor.BOTTOM_CENTER,
095 TextAnchor.BOTTOM_CENTER, -Math.PI / 2.0,
096 CategoryLabelWidthType.CATEGORY, 0.9f
097 ), // LEFT
098 new CategoryLabelPosition(
099 RectangleAnchor.LEFT, TextBlockAnchor.TOP_CENTER,
100 TextAnchor.TOP_CENTER, -Math.PI / 2.0,
101 CategoryLabelWidthType.CATEGORY, 0.90f
102 ) // RIGHT
103 );
104
105 /** DOWN_90 category label positions. */
106 public static final CategoryLabelPositions
107 DOWN_90 = new CategoryLabelPositions(
108 new CategoryLabelPosition(
109 RectangleAnchor.BOTTOM, TextBlockAnchor.CENTER_RIGHT,
110 TextAnchor.CENTER_RIGHT, Math.PI / 2.0,
111 CategoryLabelWidthType.RANGE, 0.30f
112 ), // TOP
113 new CategoryLabelPosition(
114 RectangleAnchor.TOP, TextBlockAnchor.CENTER_LEFT,
115 TextAnchor.CENTER_LEFT, Math.PI / 2.0,
116 CategoryLabelWidthType.RANGE, 0.30f
117 ), // BOTTOM
118 new CategoryLabelPosition(
119 RectangleAnchor.RIGHT, TextBlockAnchor.TOP_CENTER,
120 TextAnchor.TOP_CENTER, Math.PI / 2.0,
121 CategoryLabelWidthType.CATEGORY, 0.90f
122 ), // LEFT
123 new CategoryLabelPosition(
124 RectangleAnchor.LEFT, TextBlockAnchor.BOTTOM_CENTER,
125 TextAnchor.BOTTOM_CENTER, Math.PI / 2.0,
126 CategoryLabelWidthType.CATEGORY, 0.90f
127 ) // RIGHT
128 );
129
130 /** UP_45 category label positions. */
131 public static final CategoryLabelPositions UP_45
132 = createUpRotationLabelPositions(Math.PI / 4.0);
133
134 /** DOWN_45 category label positions. */
135 public static final CategoryLabelPositions DOWN_45
136 = createDownRotationLabelPositions(Math.PI / 4.0);
137
138 /**
139 * Creates a new instance where the category labels angled upwards by the
140 * specified amount.
141 *
142 * @param angle the rotation angle (should be < Math.PI / 2.0).
143 *
144 * @return A category label position specification.
145 */
146 public static CategoryLabelPositions createUpRotationLabelPositions(
147 double angle) {
148 return new CategoryLabelPositions(
149 new CategoryLabelPosition(
150 RectangleAnchor.BOTTOM, TextBlockAnchor.BOTTOM_LEFT,
151 TextAnchor.BOTTOM_LEFT, -angle,
152 CategoryLabelWidthType.RANGE, 0.50f
153 ), // TOP
154 new CategoryLabelPosition(
155 RectangleAnchor.TOP, TextBlockAnchor.TOP_RIGHT,
156 TextAnchor.TOP_RIGHT, -angle,
157 CategoryLabelWidthType.RANGE, 0.50f
158 ), // BOTTOM
159 new CategoryLabelPosition(
160 RectangleAnchor.RIGHT, TextBlockAnchor.BOTTOM_RIGHT,
161 TextAnchor.BOTTOM_RIGHT, -angle,
162 CategoryLabelWidthType.RANGE, 0.50f
163 ), // LEFT
164 new CategoryLabelPosition(
165 RectangleAnchor.LEFT, TextBlockAnchor.TOP_LEFT,
166 TextAnchor.TOP_LEFT, -angle,
167 CategoryLabelWidthType.RANGE, 0.50f
168 ) // RIGHT
169 );
170 }
171
172 /**
173 * Creates a new instance where the category labels angled downwards by the
174 * specified amount.
175 *
176 * @param angle the rotation angle (should be < Math.PI / 2.0).
177 *
178 * @return A category label position specification.
179 */
180 public static CategoryLabelPositions createDownRotationLabelPositions(
181 double angle) {
182 return new CategoryLabelPositions(
183 new CategoryLabelPosition(
184 RectangleAnchor.BOTTOM, TextBlockAnchor.BOTTOM_RIGHT,
185 TextAnchor.BOTTOM_RIGHT, angle,
186 CategoryLabelWidthType.RANGE, 0.50f
187 ), // TOP
188 new CategoryLabelPosition(
189 RectangleAnchor.TOP, TextBlockAnchor.TOP_LEFT,
190 TextAnchor.TOP_LEFT, angle,
191 CategoryLabelWidthType.RANGE, 0.50f
192 ), // BOTTOM
193 new CategoryLabelPosition(
194 RectangleAnchor.RIGHT, TextBlockAnchor.TOP_RIGHT,
195 TextAnchor.TOP_RIGHT, angle,
196 CategoryLabelWidthType.RANGE, 0.50f
197 ), // LEFT
198 new CategoryLabelPosition(
199 RectangleAnchor.LEFT, TextBlockAnchor.BOTTOM_LEFT,
200 TextAnchor.BOTTOM_LEFT, angle,
201 CategoryLabelWidthType.RANGE, 0.50f
202 ) // RIGHT
203 );
204 }
205
206 /**
207 * The label positioning details used when an axis is at the top of a
208 * chart.
209 */
210 private CategoryLabelPosition positionForAxisAtTop;
211
212 /**
213 * The label positioning details used when an axis is at the bottom of a
214 * chart.
215 */
216 private CategoryLabelPosition positionForAxisAtBottom;
217
218 /**
219 * The label positioning details used when an axis is at the left of a
220 * chart.
221 */
222 private CategoryLabelPosition positionForAxisAtLeft;
223
224 /**
225 * The label positioning details used when an axis is at the right of a
226 * chart.
227 */
228 private CategoryLabelPosition positionForAxisAtRight;
229
230 /**
231 * Default constructor.
232 */
233 public CategoryLabelPositions() {
234 this.positionForAxisAtTop = new CategoryLabelPosition();
235 this.positionForAxisAtBottom = new CategoryLabelPosition();
236 this.positionForAxisAtLeft = new CategoryLabelPosition();
237 this.positionForAxisAtRight = new CategoryLabelPosition();
238 }
239
240 /**
241 * Creates a new position specification.
242 *
243 * @param top the label position info used when an axis is at the top
244 * (<code>null</code> not permitted).
245 * @param bottom the label position info used when an axis is at the
246 * bottom (<code>null</code> not permitted).
247 * @param left the label position info used when an axis is at the left
248 * (<code>null</code> not permitted).
249 * @param right the label position info used when an axis is at the right
250 * (<code>null</code> not permitted).
251 */
252 public CategoryLabelPositions(CategoryLabelPosition top,
253 CategoryLabelPosition bottom,
254 CategoryLabelPosition left,
255 CategoryLabelPosition right) {
256
257 if (top == null) {
258 throw new IllegalArgumentException("Null 'top' argument.");
259 }
260 if (bottom == null) {
261 throw new IllegalArgumentException("Null 'bottom' argument.");
262 }
263 if (left == null) {
264 throw new IllegalArgumentException("Null 'left' argument.");
265 }
266 if (right == null) {
267 throw new IllegalArgumentException("Null 'right' argument.");
268 }
269
270 this.positionForAxisAtTop = top;
271 this.positionForAxisAtBottom = bottom;
272 this.positionForAxisAtLeft = left;
273 this.positionForAxisAtRight = right;
274
275 }
276
277 /**
278 * Returns the category label position specification for an axis at the
279 * given location.
280 *
281 * @param edge the axis location.
282 *
283 * @return The category label position specification.
284 */
285 public CategoryLabelPosition getLabelPosition(RectangleEdge edge) {
286 CategoryLabelPosition result = null;
287 if (edge == RectangleEdge.TOP) {
288 result = this.positionForAxisAtTop;
289 }
290 else if (edge == RectangleEdge.BOTTOM) {
291 result = this.positionForAxisAtBottom;
292 }
293 else if (edge == RectangleEdge.LEFT) {
294 result = this.positionForAxisAtLeft;
295 }
296 else if (edge == RectangleEdge.RIGHT) {
297 result = this.positionForAxisAtRight;
298 }
299 return result;
300 }
301
302 /**
303 * Returns a new instance based on an existing instance but with the top
304 * position changed.
305 *
306 * @param base the base (<code>null</code> not permitted).
307 * @param top the top position (<code>null</code> not permitted).
308 *
309 * @return A new instance (never <code>null</code>).
310 */
311 public static CategoryLabelPositions replaceTopPosition(
312 CategoryLabelPositions base, CategoryLabelPosition top) {
313
314 if (base == null) {
315 throw new IllegalArgumentException("Null 'base' argument.");
316 }
317 if (top == null) {
318 throw new IllegalArgumentException("Null 'top' argument.");
319 }
320
321 return new CategoryLabelPositions(
322 top,
323 base.getLabelPosition(RectangleEdge.BOTTOM),
324 base.getLabelPosition(RectangleEdge.LEFT),
325 base.getLabelPosition(RectangleEdge.RIGHT)
326 );
327 }
328
329 /**
330 * Returns a new instance based on an existing instance but with the bottom
331 * position changed.
332 *
333 * @param base the base (<code>null</code> not permitted).
334 * @param bottom the bottom position (<code>null</code> not permitted).
335 *
336 * @return A new instance (never <code>null</code>).
337 */
338 public static CategoryLabelPositions replaceBottomPosition(
339 CategoryLabelPositions base, CategoryLabelPosition bottom) {
340
341 if (base == null) {
342 throw new IllegalArgumentException("Null 'base' argument.");
343 }
344 if (bottom == null) {
345 throw new IllegalArgumentException("Null 'bottom' argument.");
346 }
347
348 return new CategoryLabelPositions(
349 base.getLabelPosition(RectangleEdge.TOP),
350 bottom,
351 base.getLabelPosition(RectangleEdge.LEFT),
352 base.getLabelPosition(RectangleEdge.RIGHT)
353 );
354 }
355
356 /**
357 * Returns a new instance based on an existing instance but with the left
358 * position changed.
359 *
360 * @param base the base (<code>null</code> not permitted).
361 * @param left the left position (<code>null</code> not permitted).
362 *
363 * @return A new instance (never <code>null</code>).
364 */
365 public static CategoryLabelPositions replaceLeftPosition(
366 CategoryLabelPositions base, CategoryLabelPosition left) {
367
368 if (base == null) {
369 throw new IllegalArgumentException("Null 'base' argument.");
370 }
371 if (left == null) {
372 throw new IllegalArgumentException("Null 'left' argument.");
373 }
374
375 return new CategoryLabelPositions(
376 base.getLabelPosition(RectangleEdge.TOP),
377 base.getLabelPosition(RectangleEdge.BOTTOM),
378 left,
379 base.getLabelPosition(RectangleEdge.RIGHT)
380 );
381 }
382
383 /**
384 * Returns a new instance based on an existing instance but with the right
385 * position changed.
386 *
387 * @param base the base (<code>null</code> not permitted).
388 * @param right the right position (<code>null</code> not permitted).
389 *
390 * @return A new instance (never <code>null</code>).
391 */
392 public static CategoryLabelPositions replaceRightPosition(
393 CategoryLabelPositions base, CategoryLabelPosition right) {
394
395 if (base == null) {
396 throw new IllegalArgumentException("Null 'base' argument.");
397 }
398 if (right == null) {
399 throw new IllegalArgumentException("Null 'right' argument.");
400 }
401
402 return new CategoryLabelPositions(
403 base.getLabelPosition(RectangleEdge.TOP),
404 base.getLabelPosition(RectangleEdge.BOTTOM),
405 base.getLabelPosition(RectangleEdge.LEFT),
406 right
407 );
408 }
409
410 /**
411 * Returns <code>true</code> if this object is equal to the specified
412 * object, and <code>false</code> otherwise.
413 *
414 * @param obj the other object.
415 *
416 * @return A boolean.
417 */
418 public boolean equals(Object obj) {
419
420 if (this == obj) {
421 return true;
422 }
423 if (!(obj instanceof CategoryLabelPositions)) {
424 return false;
425 }
426
427 CategoryLabelPositions that = (CategoryLabelPositions) obj;
428 if (!this.positionForAxisAtTop.equals(that.positionForAxisAtTop)) {
429 return false;
430 }
431 if (!this.positionForAxisAtBottom.equals(
432 that.positionForAxisAtBottom)) {
433 return false;
434 }
435 if (!this.positionForAxisAtLeft.equals(that.positionForAxisAtLeft)) {
436 return false;
437 }
438 if (!this.positionForAxisAtRight.equals(that.positionForAxisAtRight)) {
439 return false;
440 }
441
442 return true;
443
444 }
445
446 /**
447 * Returns a hash code for this object.
448 *
449 * @return A hash code.
450 */
451 public int hashCode() {
452 int result = 19;
453 result = 37 * result + this.positionForAxisAtTop.hashCode();
454 result = 37 * result + this.positionForAxisAtBottom.hashCode();
455 result = 37 * result + this.positionForAxisAtLeft.hashCode();
456 result = 37 * result + this.positionForAxisAtRight.hashCode();
457 return result;
458 }
459 }