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