001/* =========================================================== 002 * JFreeChart : a free chart library for the Java(tm) platform 003 * =========================================================== 004 * 005 * (C) Copyright 2000-present, by David Gilbert 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 * [Oracle and Java are registered trademarks of Oracle and/or its affiliates. 025 * Other names may be trademarks of their respective owners.] 026 * 027 * ---------------------- 028 * CenterArrangement.java 029 * ---------------------- 030 * (C) Copyright 2005-present, by David Gilbert. 031 * 032 * Original Author: David Gilbert; 033 * Contributor(s): -; 034 * 035 */ 036 037package org.jfree.chart.block; 038 039import java.awt.Graphics2D; 040import java.awt.geom.Rectangle2D; 041import java.io.Serializable; 042import java.util.List; 043import org.jfree.chart.ui.Size2D; 044 045/** 046 * Arranges a block in the center of its container. This class is immutable. 047 */ 048public class CenterArrangement implements Arrangement, Serializable { 049 050 /** For serialization. */ 051 private static final long serialVersionUID = -353308149220382047L; 052 053 /** 054 * Creates a new instance. 055 */ 056 public CenterArrangement() { 057 } 058 059 /** 060 * Adds a block to be managed by this instance. This method is usually 061 * called by the {@link BlockContainer}, you shouldn't need to call it 062 * directly. 063 * 064 * @param block the block. 065 * @param key a key that controls the position of the block. 066 */ 067 @Override 068 public void add(Block block, Object key) { 069 // since the flow layout is relatively straightforward, 070 // no information needs to be recorded here 071 } 072 073 /** 074 * Calculates and sets the bounds of all the items in the specified 075 * container, subject to the given constraint. The {@code Graphics2D} 076 * can be used by some items (particularly items containing text) to 077 * calculate sizing parameters. 078 * 079 * @param container the container whose items are being arranged. 080 * @param g2 the graphics device. 081 * @param constraint the size constraint. 082 * 083 * @return The size of the container after arrangement of the contents. 084 */ 085 @Override 086 public Size2D arrange(BlockContainer container, Graphics2D g2, 087 RectangleConstraint constraint) { 088 089 LengthConstraintType w = constraint.getWidthConstraintType(); 090 LengthConstraintType h = constraint.getHeightConstraintType(); 091 if (w == LengthConstraintType.NONE) { 092 if (h == LengthConstraintType.NONE) { 093 return arrangeNN(container, g2); 094 } 095 else if (h == LengthConstraintType.FIXED) { 096 throw new RuntimeException("Not implemented."); 097 } 098 else if (h == LengthConstraintType.RANGE) { 099 throw new RuntimeException("Not implemented."); 100 } 101 } 102 else if (w == LengthConstraintType.FIXED) { 103 if (h == LengthConstraintType.NONE) { 104 return arrangeFN(container, g2, constraint); 105 } 106 else if (h == LengthConstraintType.FIXED) { 107 throw new RuntimeException("Not implemented."); 108 } 109 else if (h == LengthConstraintType.RANGE) { 110 throw new RuntimeException("Not implemented."); 111 } 112 } 113 else if (w == LengthConstraintType.RANGE) { 114 if (h == LengthConstraintType.NONE) { 115 return arrangeRN(container, g2, constraint); 116 } 117 else if (h == LengthConstraintType.FIXED) { 118 return arrangeRF(container, g2, constraint); 119 } 120 else if (h == LengthConstraintType.RANGE) { 121 return arrangeRR(container, g2, constraint); 122 } 123 } 124 throw new IllegalArgumentException("Unknown LengthConstraintType."); 125 126 } 127 128 /** 129 * Arranges the blocks in the container with a fixed width and no height 130 * constraint. 131 * 132 * @param container the container. 133 * @param g2 the graphics device. 134 * @param constraint the constraint. 135 * 136 * @return The size. 137 */ 138 protected Size2D arrangeFN(BlockContainer container, Graphics2D g2, 139 RectangleConstraint constraint) { 140 141 List blocks = container.getBlocks(); 142 Block b = (Block) blocks.get(0); 143 Size2D s = b.arrange(g2, RectangleConstraint.NONE); 144 double width = constraint.getWidth(); 145 Rectangle2D bounds = new Rectangle2D.Double((width - s.width) / 2.0, 146 0.0, s.width, s.height); 147 b.setBounds(bounds); 148 return new Size2D((width - s.width) / 2.0, s.height); 149 } 150 151 /** 152 * Arranges the blocks in the container with a fixed with and a range 153 * constraint on the height. 154 * 155 * @param container the container. 156 * @param g2 the graphics device. 157 * @param constraint the constraint. 158 * 159 * @return The size following the arrangement. 160 */ 161 protected Size2D arrangeFR(BlockContainer container, Graphics2D g2, 162 RectangleConstraint constraint) { 163 164 Size2D s = arrangeFN(container, g2, constraint); 165 if (constraint.getHeightRange().contains(s.height)) { 166 return s; 167 } 168 else { 169 RectangleConstraint c = constraint.toFixedHeight( 170 constraint.getHeightRange().constrain(s.getHeight())); 171 return arrangeFF(container, g2, c); 172 } 173 } 174 175 /** 176 * Arranges the blocks in the container with the overall height and width 177 * specified as fixed constraints. 178 * 179 * @param container the container. 180 * @param g2 the graphics device. 181 * @param constraint the constraint. 182 * 183 * @return The size following the arrangement. 184 */ 185 protected Size2D arrangeFF(BlockContainer container, Graphics2D g2, 186 RectangleConstraint constraint) { 187 188 // TODO: implement this properly 189 return arrangeFN(container, g2, constraint); 190 } 191 192 /** 193 * Arranges the blocks with the overall width and height to fit within 194 * specified ranges. 195 * 196 * @param container the container. 197 * @param g2 the graphics device. 198 * @param constraint the constraint. 199 * 200 * @return The size after the arrangement. 201 */ 202 protected Size2D arrangeRR(BlockContainer container, Graphics2D g2, 203 RectangleConstraint constraint) { 204 205 // first arrange without constraints, and see if this fits within 206 // the required ranges... 207 Size2D s1 = arrangeNN(container, g2); 208 if (constraint.getWidthRange().contains(s1.width)) { 209 return s1; // TODO: we didn't check the height yet 210 } 211 else { 212 RectangleConstraint c = constraint.toFixedWidth( 213 constraint.getWidthRange().getUpperBound()); 214 return arrangeFR(container, g2, c); 215 } 216 } 217 218 /** 219 * Arranges the blocks in the container with a range constraint on the 220 * width and a fixed height. 221 * 222 * @param container the container. 223 * @param g2 the graphics device. 224 * @param constraint the constraint. 225 * 226 * @return The size following the arrangement. 227 */ 228 protected Size2D arrangeRF(BlockContainer container, Graphics2D g2, 229 RectangleConstraint constraint) { 230 231 Size2D s = arrangeNF(container, g2, constraint); 232 if (constraint.getWidthRange().contains(s.width)) { 233 return s; 234 } 235 else { 236 RectangleConstraint c = constraint.toFixedWidth( 237 constraint.getWidthRange().constrain(s.getWidth())); 238 return arrangeFF(container, g2, c); 239 } 240 } 241 242 /** 243 * Arranges the block with a range constraint on the width, and no 244 * constraint on the height. 245 * 246 * @param container the container. 247 * @param g2 the graphics device. 248 * @param constraint the constraint. 249 * 250 * @return The size following the arrangement. 251 */ 252 protected Size2D arrangeRN(BlockContainer container, Graphics2D g2, 253 RectangleConstraint constraint) { 254 // first arrange without constraints, then see if the width fits 255 // within the required range...if not, call arrangeFN() at max width 256 Size2D s1 = arrangeNN(container, g2); 257 if (constraint.getWidthRange().contains(s1.width)) { 258 return s1; 259 } 260 else { 261 RectangleConstraint c = constraint.toFixedWidth( 262 constraint.getWidthRange().getUpperBound()); 263 return arrangeFN(container, g2, c); 264 } 265 } 266 267 /** 268 * Arranges the blocks without any constraints. This puts all blocks 269 * into a single row. 270 * 271 * @param container the container. 272 * @param g2 the graphics device. 273 * 274 * @return The size after the arrangement. 275 */ 276 protected Size2D arrangeNN(BlockContainer container, Graphics2D g2) { 277 List blocks = container.getBlocks(); 278 Block b = (Block) blocks.get(0); 279 Size2D s = b.arrange(g2, RectangleConstraint.NONE); 280 b.setBounds(new Rectangle2D.Double(0.0, 0.0, s.width, s.height)); 281 return new Size2D(s.width, s.height); 282 } 283 284 /** 285 * Arranges the blocks with no width constraint and a fixed height 286 * constraint. This puts all blocks into a single row. 287 * 288 * @param container the container. 289 * @param g2 the graphics device. 290 * @param constraint the constraint. 291 * 292 * @return The size after the arrangement. 293 */ 294 protected Size2D arrangeNF(BlockContainer container, Graphics2D g2, 295 RectangleConstraint constraint) { 296 // TODO: for now we are ignoring the height constraint 297 return arrangeNN(container, g2); 298 } 299 300 /** 301 * Clears any cached information. 302 */ 303 @Override 304 public void clear() { 305 // no action required. 306 } 307 308 /** 309 * Tests this instance for equality with an arbitrary object. 310 * 311 * @param obj the object ({@code null} permitted). 312 * 313 * @return A boolean. 314 */ 315 @Override 316 public boolean equals(Object obj) { 317 if (obj == this) { 318 return true; 319 } 320 if (!(obj instanceof CenterArrangement)) { 321 return false; 322 } 323 return true; 324 } 325 326}