|  | /* 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; | 
|  | } |