| /* GridLayout.java -- Grid-based layout engine | |
| Copyright (C) 1999, 2000, 2002, 2004 Free Software Foundation | |
| This file is part of GNU Classpath. | |
| GNU Classpath is free software; you can redistribute it and/or modify | |
| it under the terms of the GNU General Public License as published by | |
| the Free Software Foundation; either version 2, or (at your option) | |
| any later version. | |
| GNU Classpath is distributed in the hope that it will be useful, but | |
| WITHOUT ANY WARRANTY; without even the implied warranty of | |
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
| General Public License for more details. | |
| You should have received a copy of the GNU General Public License | |
| along with GNU Classpath; see the file COPYING. If not, write to the | |
| Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA | |
| 02110-1301 USA. | |
| Linking this library statically or dynamically with other modules is | |
| making a combined work based on this library. Thus, the terms and | |
| conditions of the GNU General Public License cover the whole | |
| combination. | |
| As a special exception, the copyright holders of this library give you | |
| permission to link this library with independent modules to produce an | |
| executable, regardless of the license terms of these independent | |
| modules, and to copy and distribute the resulting executable under | |
| terms of your choice, provided that you also meet, for each linked | |
| independent module, the terms and conditions of the license of that | |
| module. An independent module is a module which is not derived from | |
| or based on this library. If you modify this library, you may extend | |
| this exception to your version of the library, but you are not | |
| obligated to do so. If you do not wish to do so, delete this | |
| exception statement from your version. */ | |
| package java.awt; | |
| import java.io.Serializable; | |
| /** This class implements a grid-based layout scheme. Components are | |
| * all given the same size and are laid out from left to right and top | |
| * to bottom. A GridLayout is configured with a number of rows and a | |
| * number of columns. If both are specified, then the number of | |
| * columns is ignored and is derived from the number of rows and the | |
| * total number of components. If either is zero then that dimension | |
| * is computed based on the actual size of the container. An | |
| * exception is thrown if an attempt is made to set both the number of | |
| * rows and the number of columns to 0. This class also supports | |
| * horizontal and vertical gaps; these are used as spacing between | |
| * cells. | |
| * | |
| * @author Tom Tromey (tromey@redhat.com) | |
| * @author Aaron M. Renn (arenn@urbanophile.com) | |
| */ | |
| public class GridLayout implements LayoutManager, Serializable | |
| { | |
| static final long serialVersionUID = -7411804673224730901L; | |
| /** Add a new component to the layout. This particular implementation | |
| * does nothing. | |
| * @param name The name of the component to add. | |
| * @param comp The component to add. | |
| */ | |
| public void addLayoutComponent (String name, Component comp) | |
| { | |
| // Nothing. | |
| } | |
| /** Return the number of columns in this layout. */ | |
| public int getColumns () | |
| { | |
| return cols; | |
| } | |
| /** Return the horizontal gap. */ | |
| public int getHgap () | |
| { | |
| return hgap; | |
| } | |
| /** Return the number of rows in this layout. */ | |
| public int getRows () | |
| { | |
| return rows; | |
| } | |
| /** Return the vertical gap. */ | |
| public int getVgap () | |
| { | |
| return vgap; | |
| } | |
| /** Create a new <code>GridLayout</code> with one row and any number | |
| * of columns. Both gaps are set to 0. | |
| */ | |
| public GridLayout () | |
| { | |
| this (1, 0, 0, 0); | |
| } | |
| /** Create a new <code>GridLayout</code> with the specified number | |
| * of rows and columns. Both gaps are set to 0. Note that the row | |
| * and column settings cannot both be zero. If both the row and | |
| * column values are non-zero, the rows value takes precedence. | |
| * @param rows Number of rows | |
| * @param cols Number of columns | |
| * @exception IllegalArgumentException If rows and columns are both | |
| * 0, or if either are negative | |
| */ | |
| public GridLayout (int rows, int cols) | |
| { | |
| this (rows, cols, 0, 0); | |
| } | |
| /** Create a new GridLayout with the specified number of rows and | |
| * columns and the specified gaps. | |
| * Note that the row and column settings cannot both be | |
| * zero. If both the row and column values are non-zero, the rows value | |
| * takes precedence. | |
| * @param rows Number of rows | |
| * @param cols Number of columns | |
| * @param hgap The horizontal gap | |
| * @param vgap The vertical gap | |
| * @exception IllegalArgumentException If rows and columns are both | |
| * 0, if either are negative, or if either gap is negative | |
| */ | |
| public GridLayout (int rows, int cols, int hgap, int vgap) | |
| { | |
| if (rows < 0) | |
| throw new IllegalArgumentException ("number of rows cannot be negative"); | |
| if (cols < 0) | |
| throw new IllegalArgumentException ("number of columns cannot be negative"); | |
| if (rows == 0 && cols == 0) | |
| throw new IllegalArgumentException ("both rows and columns cannot be 0"); | |
| if (hgap < 0) | |
| throw new IllegalArgumentException ("horizontal gap must be nonnegative"); | |
| if (vgap < 0) | |
| throw new IllegalArgumentException ("vertical gap must be nonnegative"); | |
| this.rows = rows; | |
| this.cols = cols; | |
| this.hgap = hgap; | |
| this.vgap = vgap; | |
| } | |
| /** Lay out the container's components based on current settings. | |
| * The free space in the container is divided evenly into the specified | |
| * number of rows and columns in this object. | |
| * @param parent The container to lay out | |
| */ | |
| public void layoutContainer (Container parent) | |
| { | |
| synchronized (parent.getTreeLock ()) | |
| { | |
| int num = parent.ncomponents; | |
| // There's no point, and handling this would mean adding special | |
| // cases. | |
| if (num == 0) | |
| return; | |
| // This is more efficient than calling getComponents(). | |
| Component[] comps = parent.component; | |
| int real_rows = rows; | |
| int real_cols = cols; | |
| if (real_rows == 0) | |
| real_rows = (num + real_cols - 1) / real_cols; | |
| else | |
| real_cols = (num + real_rows - 1) / real_rows; | |
| // We might have less than a single row. In this case we expand | |
| // to fill. | |
| if (num < real_cols) | |
| real_cols = num; | |
| Dimension d = parent.getSize (); | |
| Insets ins = parent.getInsets (); | |
| // Compute width and height of each cell in the grid. | |
| int tw = d.width - ins.left - ins.right; | |
| tw = (tw - (real_cols - 1) * hgap) / real_cols; | |
| int th = d.height - ins.top - ins.bottom; | |
| th = (th - (real_rows - 1) * vgap) / real_rows; | |
| // If the cells are too small, still try to do something. | |
| if (tw < 0) | |
| tw = 1; | |
| if (th < 0) | |
| th = 1; | |
| int x = ins.left; | |
| int y = ins.top; | |
| int i = 0; | |
| int recount = 0; | |
| while (i < num) | |
| { | |
| comps[i].setBounds (x, y, tw, th); | |
| ++i; | |
| ++recount; | |
| if (recount == real_cols) | |
| { | |
| recount = 0; | |
| y += vgap + th; | |
| x = ins.left; | |
| } | |
| else | |
| x += hgap + tw; | |
| } | |
| } | |
| } | |
| /** Get the minimum layout size of the container. | |
| * @param cont The parent container | |
| */ | |
| public Dimension minimumLayoutSize (Container cont) | |
| { | |
| return getSize (cont, true); | |
| } | |
| /** Get the preferred layout size of the container. | |
| * @param cont The parent container | |
| */ | |
| public Dimension preferredLayoutSize (Container cont) | |
| { | |
| return getSize (cont, false); | |
| } | |
| /** Remove the indicated component from this layout manager. | |
| * This particular implementation does nothing. | |
| * @param comp The component to remove | |
| */ | |
| public void removeLayoutComponent (Component comp) | |
| { | |
| // Nothing. | |
| } | |
| /** Set the number of columns. | |
| * @param newCols | |
| * @exception IllegalArgumentException If the number of columns is | |
| * negative, or if the number of columns is zero and the number | |
| * of rows is already 0. | |
| */ | |
| public void setColumns (int newCols) | |
| { | |
| if (newCols < 0) | |
| throw new IllegalArgumentException ("number of columns cannot be negative"); | |
| if (newCols == 0 && rows == 0) | |
| throw new IllegalArgumentException ("number of rows is already 0"); | |
| this.cols = newCols; | |
| } | |
| /** Set the horizontal gap. An Exception is not thrown if hgap < 0. | |
| * @param hgap The horizontal gap | |
| */ | |
| public void setHgap (int hgap) | |
| { | |
| this.hgap = hgap; | |
| } | |
| /** Set the number of rows | |
| * @param newRows | |
| * @exception IllegalArgumentException If the number of rows is | |
| * negative, or if the number of rows is zero and the number | |
| * of columns is already 0. | |
| */ | |
| public void setRows (int newRows) | |
| { | |
| if (newRows < 0) | |
| throw new IllegalArgumentException ("number of rows cannot be negative"); | |
| if (newRows == 0 && cols == 0) | |
| throw new IllegalArgumentException ("number of columns is already 0"); | |
| this.rows = newRows; | |
| } | |
| /** Set the vertical gap. An Exception is not thrown if vgap < 0. | |
| * @param vgap The vertical gap | |
| */ | |
| public void setVgap (int vgap) | |
| { | |
| this.vgap = vgap; | |
| } | |
| /** Return String description of this object. */ | |
| public String toString () | |
| { | |
| return (getClass ().getName () + "[" | |
| + ",hgap=" + hgap + ",vgap=" + vgap | |
| + ",rows=" + rows + ",cols=" + cols | |
| + "]"); | |
| } | |
| // This method is used to compute the various sizes. | |
| private Dimension getSize (Container parent, boolean is_min) | |
| { | |
| synchronized (parent.getTreeLock ()) | |
| { | |
| int w = 0, h = 0, num = parent.ncomponents; | |
| // This is more efficient than calling getComponents(). | |
| Component[] comps = parent.component; | |
| for (int i = 0; i < num; ++i) | |
| { | |
| Dimension d; | |
| if (is_min) | |
| d = comps[i].getMinimumSize (); | |
| else | |
| d = comps[i].getPreferredSize (); | |
| w = Math.max (d.width, w); | |
| h = Math.max (d.height, h); | |
| } | |
| int real_rows = rows; | |
| int real_cols = cols; | |
| if (real_rows == 0) | |
| real_rows = (num + real_cols - 1) / real_cols; | |
| else | |
| real_cols = (num + real_rows - 1) / real_rows; | |
| Insets ins = parent.getInsets (); | |
| // We subtract out an extra gap here because the gaps are only | |
| // between cells. | |
| w = ins.left + ins.right + real_cols * (w + hgap) - hgap; | |
| h = ins.top + ins.bottom + real_rows * (h + vgap) - vgap; | |
| return new Dimension (w, h); | |
| } | |
| } | |
| /** | |
| * @serial The number of columns in the grid. | |
| */ | |
| private int cols; | |
| /** | |
| * @serial The number of rows in the grid. | |
| */ | |
| private int rows; | |
| /** | |
| * @serial The horizontal gap between columns | |
| */ | |
| private int hgap; | |
| /** | |
| * @serial The vertical gap between rows | |
| */ | |
| private int vgap; | |
| } |