1 /* GridLayout.java -- Grid-based layout engine 2 Copyright (C) 1999, 2000, 2002, 2004 Free Software Foundation 3 4 This file is part of GNU Classpath. 5 6 GNU Classpath is free software; you can redistribute it and/or modify 7 it under the terms of the GNU General Public License as published by 8 the Free Software Foundation; either version 2, or (at your option) 9 any later version. 10 11 GNU Classpath is distributed in the hope that it will be useful, but 12 WITHOUT ANY WARRANTY; without even the implied warranty of 13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 General Public License for more details. 15 16 You should have received a copy of the GNU General Public License 17 along with GNU Classpath; see the file COPYING. If not, write to the 18 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 19 02110-1301 USA. 20 21 Linking this library statically or dynamically with other modules is 22 making a combined work based on this library. Thus, the terms and 23 conditions of the GNU General Public License cover the whole 24 combination. 25 26 As a special exception, the copyright holders of this library give you 27 permission to link this library with independent modules to produce an 28 executable, regardless of the license terms of these independent 29 modules, and to copy and distribute the resulting executable under 30 terms of your choice, provided that you also meet, for each linked 31 independent module, the terms and conditions of the license of that 32 module. An independent module is a module which is not derived from 33 or based on this library. If you modify this library, you may extend 34 this exception to your version of the library, but you are not 35 obligated to do so. If you do not wish to do so, delete this 36 exception statement from your version. */ 37 38 39 package java.awt; 40 41 import java.io.Serializable; 42 43 /** This class implements a grid-based layout scheme. Components are 44 * all given the same size and are laid out from left to right and top 45 * to bottom. A GridLayout is configured with a number of rows and a 46 * number of columns. If both are specified, then the number of 47 * columns is ignored and is derived from the number of rows and the 48 * total number of components. If either is zero then that dimension 49 * is computed based on the actual size of the container. An 50 * exception is thrown if an attempt is made to set both the number of 51 * rows and the number of columns to 0. This class also supports 52 * horizontal and vertical gaps; these are used as spacing between 53 * cells. 54 * 55 * @author Tom Tromey (tromey@redhat.com) 56 * @author Aaron M. Renn (arenn@urbanophile.com) 57 */ 58 public class GridLayout implements LayoutManager, Serializable 59 { 60 static final long serialVersionUID = -7411804673224730901L; 61 62 /** Add a new component to the layout. This particular implementation 63 * does nothing. 64 * @param name The name of the component to add. 65 * @param comp The component to add. 66 */ addLayoutComponent(String name, Component comp)67 public void addLayoutComponent (String name, Component comp) 68 { 69 // Nothing. 70 } 71 72 /** Return the number of columns in this layout. */ getColumns()73 public int getColumns () 74 { 75 return cols; 76 } 77 78 /** Return the horizontal gap. */ getHgap()79 public int getHgap () 80 { 81 return hgap; 82 } 83 84 /** Return the number of rows in this layout. */ getRows()85 public int getRows () 86 { 87 return rows; 88 } 89 90 /** Return the vertical gap. */ getVgap()91 public int getVgap () 92 { 93 return vgap; 94 } 95 96 /** Create a new <code>GridLayout</code> with one row and any number 97 * of columns. Both gaps are set to 0. 98 */ GridLayout()99 public GridLayout () 100 { 101 this (1, 0, 0, 0); 102 } 103 104 /** Create a new <code>GridLayout</code> with the specified number 105 * of rows and columns. Both gaps are set to 0. Note that the row 106 * and column settings cannot both be zero. If both the row and 107 * column values are non-zero, the rows value takes precedence. 108 * @param rows Number of rows 109 * @param cols Number of columns 110 * @exception IllegalArgumentException If rows and columns are both 111 * 0, or if either are negative 112 */ GridLayout(int rows, int cols)113 public GridLayout (int rows, int cols) 114 { 115 this (rows, cols, 0, 0); 116 } 117 118 /** Create a new GridLayout with the specified number of rows and 119 * columns and the specified gaps. 120 * Note that the row and column settings cannot both be 121 * zero. If both the row and column values are non-zero, the rows value 122 * takes precedence. 123 * @param rows Number of rows 124 * @param cols Number of columns 125 * @param hgap The horizontal gap 126 * @param vgap The vertical gap 127 * @exception IllegalArgumentException If rows and columns are both 128 * 0, if either are negative, or if either gap is negative 129 */ GridLayout(int rows, int cols, int hgap, int vgap)130 public GridLayout (int rows, int cols, int hgap, int vgap) 131 { 132 if (rows < 0) 133 throw new IllegalArgumentException ("number of rows cannot be negative"); 134 if (cols < 0) 135 throw new IllegalArgumentException ("number of columns cannot be negative"); 136 if (rows == 0 && cols == 0) 137 throw new IllegalArgumentException ("both rows and columns cannot be 0"); 138 if (hgap < 0) 139 throw new IllegalArgumentException ("horizontal gap must be nonnegative"); 140 if (vgap < 0) 141 throw new IllegalArgumentException ("vertical gap must be nonnegative"); 142 this.rows = rows; 143 this.cols = cols; 144 this.hgap = hgap; 145 this.vgap = vgap; 146 } 147 148 /** Lay out the container's components based on current settings. 149 * The free space in the container is divided evenly into the specified 150 * number of rows and columns in this object. 151 * @param parent The container to lay out 152 */ layoutContainer(Container parent)153 public void layoutContainer (Container parent) 154 { 155 synchronized (parent.getTreeLock ()) 156 { 157 int num = parent.ncomponents; 158 159 // There's no point, and handling this would mean adding special 160 // cases. 161 if (num == 0) 162 return; 163 164 // This is more efficient than calling getComponents(). 165 Component[] comps = parent.component; 166 167 int real_rows = rows; 168 int real_cols = cols; 169 if (real_rows == 0) 170 real_rows = (num + real_cols - 1) / real_cols; 171 else 172 real_cols = (num + real_rows - 1) / real_rows; 173 174 // We might have less than a single row. In this case we expand 175 // to fill. 176 if (num < real_cols) 177 real_cols = num; 178 179 Dimension d = parent.getSize (); 180 Insets ins = parent.getInsets (); 181 182 // Compute width and height of each cell in the grid. 183 int tw = d.width - ins.left - ins.right; 184 tw = (tw - (real_cols - 1) * hgap) / real_cols; 185 int th = d.height - ins.top - ins.bottom; 186 th = (th - (real_rows - 1) * vgap) / real_rows; 187 188 // If the cells are too small, still try to do something. 189 if (tw < 0) 190 tw = 1; 191 if (th < 0) 192 th = 1; 193 194 int x = ins.left; 195 int y = ins.top; 196 int i = 0; 197 int recount = 0; 198 199 while (i < num) 200 { 201 comps[i].setBounds (x, y, tw, th); 202 203 ++i; 204 ++recount; 205 if (recount == real_cols) 206 { 207 recount = 0; 208 y += vgap + th; 209 x = ins.left; 210 } 211 else 212 x += hgap + tw; 213 } 214 } 215 } 216 217 /** Get the minimum layout size of the container. 218 * @param cont The parent container 219 */ minimumLayoutSize(Container cont)220 public Dimension minimumLayoutSize (Container cont) 221 { 222 return getSize (cont, true); 223 } 224 225 /** Get the preferred layout size of the container. 226 * @param cont The parent container 227 */ preferredLayoutSize(Container cont)228 public Dimension preferredLayoutSize (Container cont) 229 { 230 return getSize (cont, false); 231 } 232 233 /** Remove the indicated component from this layout manager. 234 * This particular implementation does nothing. 235 * @param comp The component to remove 236 */ removeLayoutComponent(Component comp)237 public void removeLayoutComponent (Component comp) 238 { 239 // Nothing. 240 } 241 242 /** Set the number of columns. 243 * @param newCols 244 * @exception IllegalArgumentException If the number of columns is 245 * negative, or if the number of columns is zero and the number 246 * of rows is already 0. 247 */ setColumns(int newCols)248 public void setColumns (int newCols) 249 { 250 if (newCols < 0) 251 throw new IllegalArgumentException ("number of columns cannot be negative"); 252 if (newCols == 0 && rows == 0) 253 throw new IllegalArgumentException ("number of rows is already 0"); 254 this.cols = newCols; 255 } 256 257 /** Set the horizontal gap. An Exception is not thrown if hgap < 0. 258 * @param hgap The horizontal gap 259 */ setHgap(int hgap)260 public void setHgap (int hgap) 261 { 262 this.hgap = hgap; 263 } 264 265 /** Set the number of rows 266 * @param newRows 267 * @exception IllegalArgumentException If the number of rows is 268 * negative, or if the number of rows is zero and the number 269 * of columns is already 0. 270 */ setRows(int newRows)271 public void setRows (int newRows) 272 { 273 if (newRows < 0) 274 throw new IllegalArgumentException ("number of rows cannot be negative"); 275 if (newRows == 0 && cols == 0) 276 throw new IllegalArgumentException ("number of columns is already 0"); 277 this.rows = newRows; 278 } 279 280 /** Set the vertical gap. An Exception is not thrown if vgap < 0. 281 * @param vgap The vertical gap 282 */ setVgap(int vgap)283 public void setVgap (int vgap) 284 { 285 this.vgap = vgap; 286 } 287 288 /** Return String description of this object. */ toString()289 public String toString () 290 { 291 return (getClass ().getName () + "[" 292 + "hgap=" + hgap + ",vgap=" + vgap 293 + ",rows=" + rows + ",cols=" + cols 294 + "]"); 295 } 296 297 // This method is used to compute the various sizes. getSize(Container parent, boolean is_min)298 private Dimension getSize (Container parent, boolean is_min) 299 { 300 synchronized (parent.getTreeLock ()) 301 { 302 int w = 0, h = 0, num = parent.ncomponents; 303 // This is more efficient than calling getComponents(). 304 Component[] comps = parent.component; 305 306 for (int i = 0; i < num; ++i) 307 { 308 Dimension d; 309 310 if (is_min) 311 d = comps[i].getMinimumSize (); 312 else 313 d = comps[i].getPreferredSize (); 314 315 w = Math.max (d.width, w); 316 h = Math.max (d.height, h); 317 } 318 319 int real_rows = rows; 320 int real_cols = cols; 321 if (real_rows == 0) 322 real_rows = (num + real_cols - 1) / real_cols; 323 else 324 real_cols = (num + real_rows - 1) / real_rows; 325 326 Insets ins = parent.getInsets (); 327 // We subtract out an extra gap here because the gaps are only 328 // between cells. 329 w = ins.left + ins.right + real_cols * (w + hgap) - hgap; 330 h = ins.top + ins.bottom + real_rows * (h + vgap) - vgap; 331 return new Dimension (w, h); 332 } 333 } 334 335 /** 336 * @serial The number of columns in the grid. 337 */ 338 private int cols; 339 340 /** 341 * @serial The number of rows in the grid. 342 */ 343 private int rows; 344 345 /** 346 * @serial The horizontal gap between columns 347 */ 348 private int hgap; 349 350 /** 351 * @serial The vertical gap between rows 352 */ 353 private int vgap; 354 } 355