001 /* =========================================================== 002 * JFreeChart : a free chart library for the Java(tm) platform 003 * =========================================================== 004 * 005 * (C) Copyright 2000-2008, 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-2008, 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 }