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