Frames | No Frames |
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: */ 67: public void addLayoutComponent (String name, Component comp) 68: { 69: // Nothing. 70: } 71: 72: /** Return the number of columns in this layout. */ 73: public int getColumns () 74: { 75: return cols; 76: } 77: 78: /** Return the horizontal gap. */ 79: public int getHgap () 80: { 81: return hgap; 82: } 83: 84: /** Return the number of rows in this layout. */ 85: public int getRows () 86: { 87: return rows; 88: } 89: 90: /** Return the vertical gap. */ 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: */ 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: */ 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: */ 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: */ 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: */ 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: */ 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: */ 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: */ 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: */ 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: */ 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: */ 283: public void setVgap (int vgap) 284: { 285: this.vgap = vgap; 286: } 287: 288: /** Return String description of this object. */ 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. 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: }