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 * GridArrangement.java 029 * -------------------- 030 * (C) Copyright 2005, 2007, by Object Refinery Limited. 031 * 032 * Original Author: David Gilbert (for Object Refinery Limited); 033 * Contributor(s): -; 034 * 035 * Changes: 036 * -------- 037 * 08-Feb-2005 : Version 1 (DG); 038 * 039 */ 040 041 package org.jfree.chart.block; 042 043 import java.awt.Graphics2D; 044 import java.awt.geom.Rectangle2D; 045 import java.io.Serializable; 046 import java.util.Iterator; 047 import java.util.List; 048 049 import org.jfree.ui.Size2D; 050 051 /** 052 * Arranges blocks in a grid within their container. 053 */ 054 public class GridArrangement implements Arrangement, Serializable { 055 056 /** For serialization. */ 057 private static final long serialVersionUID = -2563758090144655938L; 058 059 /** The rows. */ 060 private int rows; 061 062 /** The columns. */ 063 private int columns; 064 065 /** 066 * Creates a new grid arrangement. 067 * 068 * @param rows the row count. 069 * @param columns the column count. 070 */ 071 public GridArrangement(int rows, int columns) { 072 this.rows = rows; 073 this.columns = columns; 074 } 075 076 /** 077 * Adds a block and a key which can be used to determine the position of 078 * the block in the arrangement. This method is called by the container 079 * (you don't need to call this method directly) and gives the arrangement 080 * an opportunity to record the details if they are required. 081 * 082 * @param block the block. 083 * @param key the key (<code>null</code> permitted). 084 */ 085 public void add(Block block, Object key) { 086 // can safely ignore 087 } 088 089 /** 090 * Arranges the blocks within the specified container, subject to the given 091 * constraint. 092 * 093 * @param container the container. 094 * @param constraint the constraint. 095 * @param g2 the graphics device. 096 * 097 * @return The size following the arrangement. 098 */ 099 public Size2D arrange(BlockContainer container, Graphics2D g2, 100 RectangleConstraint constraint) { 101 LengthConstraintType w = constraint.getWidthConstraintType(); 102 LengthConstraintType h = constraint.getHeightConstraintType(); 103 if (w == LengthConstraintType.NONE) { 104 if (h == LengthConstraintType.NONE) { 105 return arrangeNN(container, g2); 106 } 107 else if (h == LengthConstraintType.FIXED) { 108 109 throw new RuntimeException("Not yet implemented."); 110 } 111 else if (h == LengthConstraintType.RANGE) { 112 // find optimum height, then map to range 113 throw new RuntimeException("Not yet implemented."); 114 } 115 } 116 else if (w == LengthConstraintType.FIXED) { 117 if (h == LengthConstraintType.NONE) { 118 // find optimum height 119 return arrangeFN(container, g2, constraint); 120 } 121 else if (h == LengthConstraintType.FIXED) { 122 return arrangeFF(container, g2, constraint); 123 } 124 else if (h == LengthConstraintType.RANGE) { 125 // find optimum height and map to range 126 return arrangeFR(container, g2, constraint); 127 } 128 } 129 else if (w == LengthConstraintType.RANGE) { 130 // find optimum width and map to range 131 if (h == LengthConstraintType.NONE) { 132 // find optimum height 133 throw new RuntimeException("Not yet implemented."); 134 } 135 else if (h == LengthConstraintType.FIXED) { 136 // fixed width 137 throw new RuntimeException("Not yet implemented."); 138 } 139 else if (h == LengthConstraintType.RANGE) { 140 throw new RuntimeException("Not yet implemented."); 141 } 142 } 143 return new Size2D(); // TODO: complete this 144 } 145 146 /** 147 * Arranges the container with no constraint on the width or height. 148 * 149 * @param container the container. 150 * @param g2 the graphics device. 151 * 152 * @return The size. 153 */ 154 protected Size2D arrangeNN(BlockContainer container, Graphics2D g2) { 155 double maxW = 0.0; 156 double maxH = 0.0; 157 List blocks = container.getBlocks(); 158 Iterator iterator = blocks.iterator(); 159 while (iterator.hasNext()) { 160 Block b = (Block) iterator.next(); 161 Size2D s = b.arrange(g2, RectangleConstraint.NONE); 162 maxW = Math.max(maxW, s.width); 163 maxH = Math.max(maxH, s.height); 164 } 165 double width = this.columns * maxW; 166 double height = this.rows * maxH; 167 RectangleConstraint c = new RectangleConstraint(width, height); 168 return arrangeFF(container, g2, c); 169 } 170 171 /** 172 * Arranges the container with a fixed overall width and height. 173 * 174 * @param container the container. 175 * @param g2 the graphics device. 176 * @param constraint the constraint. 177 * 178 * @return The size following the arrangement. 179 */ 180 protected Size2D arrangeFF(BlockContainer container, Graphics2D g2, 181 RectangleConstraint constraint) { 182 double width = constraint.getWidth() / this.columns; 183 double height = constraint.getHeight() / this.rows; 184 List blocks = container.getBlocks(); 185 for (int c = 0; c < this.columns; c++) { 186 for (int r = 0; r < this.rows; r++) { 187 int index = r * this.columns + c; 188 if (index == blocks.size()) { 189 break; 190 } 191 Block b = (Block) blocks.get(index); 192 b.setBounds(new Rectangle2D.Double( 193 c * width, r * height, width, height 194 )); 195 } 196 } 197 return new Size2D(this.columns * width, this.rows * height); 198 } 199 200 /** 201 * Arrange with a fixed width and a height within a given range. 202 * 203 * @param container the container. 204 * @param constraint the constraint. 205 * @param g2 the graphics device. 206 * 207 * @return The size of the arrangement. 208 */ 209 protected Size2D arrangeFR(BlockContainer container, Graphics2D g2, 210 RectangleConstraint constraint) { 211 212 RectangleConstraint c1 = constraint.toUnconstrainedHeight(); 213 Size2D size1 = arrange(container, g2, c1); 214 215 if (constraint.getHeightRange().contains(size1.getHeight())) { 216 return size1; 217 } 218 else { 219 double h = constraint.getHeightRange().constrain(size1.getHeight()); 220 RectangleConstraint c2 = constraint.toFixedHeight(h); 221 return arrange(container, g2, c2); 222 } 223 } 224 225 /** 226 * Arrange with a fixed width and a height within a given range. 227 * 228 * @param container the container. 229 * @param g2 the graphics device. 230 * @param constraint the constraint. 231 * 232 * @return The size of the arrangement. 233 */ 234 protected Size2D arrangeFN(BlockContainer container, Graphics2D g2, 235 RectangleConstraint constraint) { 236 237 double width = constraint.getWidth() / this.columns; 238 RectangleConstraint constraint2 = constraint.toFixedWidth(width); 239 List blocks = container.getBlocks(); 240 double maxH = 0.0; 241 for (int r = 0; r < this.rows; r++) { 242 for (int c = 0; c < this.columns; c++) { 243 int index = r * this.columns + c; 244 if (index == blocks.size()) { 245 break; 246 } 247 Block b = (Block) blocks.get(index); 248 Size2D s = b.arrange(g2, constraint2); 249 maxH = Math.max(maxH, s.getHeight()); 250 } 251 } 252 RectangleConstraint constraint3 = constraint.toFixedHeight( 253 maxH * this.rows 254 ); 255 return arrange(container, g2, constraint3); 256 } 257 258 /** 259 * Clears any cached layout information retained by the arrangement. 260 */ 261 public void clear() { 262 // nothing to clear 263 } 264 265 /** 266 * Compares this layout manager for equality with an arbitrary object. 267 * 268 * @param obj the object. 269 * 270 * @return A boolean. 271 */ 272 public boolean equals(Object obj) { 273 if (obj == this) { 274 return true; 275 } 276 if (!(obj instanceof GridArrangement)) { 277 return false; 278 } 279 GridArrangement that = (GridArrangement) obj; 280 if (this.columns != that.columns) { 281 return false; 282 } 283 if (this.rows != that.rows) { 284 return false; 285 } 286 return true; 287 } 288 289 }