GridLayout.java 11 KB

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