001 /*
002 * Copyright 1995-2006 Sun Microsystems, Inc. All Rights Reserved.
003 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
004 *
005 * This code is free software; you can redistribute it and/or modify it
006 * under the terms of the GNU General Public License version 2 only, as
007 * published by the Free Software Foundation. Sun designates this
008 * particular file as subject to the "Classpath" exception as provided
009 * by Sun in the LICENSE file that accompanied this code.
010 *
011 * This code is distributed in the hope that it will be useful, but WITHOUT
012 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
013 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
014 * version 2 for more details (a copy is included in the LICENSE file that
015 * accompanied this code).
016 *
017 * You should have received a copy of the GNU General Public License version
018 * 2 along with this work; if not, write to the Free Software Foundation,
019 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
020 *
021 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
022 * CA 95054 USA or visit www.sun.com if you need additional information or
023 * have any questions.
024 */
025
026 package java.awt;
027
028 /**
029 * The <code>GridLayout</code> class is a layout manager that
030 * lays out a container's components in a rectangular grid.
031 * The container is divided into equal-sized rectangles,
032 * and one component is placed in each rectangle.
033 * For example, the following is an applet that lays out six buttons
034 * into three rows and two columns:
035 * <p>
036 * <hr><blockquote>
037 * <pre>
038 * import java.awt.*;
039 * import java.applet.Applet;
040 * public class ButtonGrid extends Applet {
041 * public void init() {
042 * setLayout(new GridLayout(3,2));
043 * add(new Button("1"));
044 * add(new Button("2"));
045 * add(new Button("3"));
046 * add(new Button("4"));
047 * add(new Button("5"));
048 * add(new Button("6"));
049 * }
050 * }
051 * </pre></blockquote><hr>
052 * <p>
053 * If the container's <code>ComponentOrientation</code> property is horizontal
054 * and left-to-right, the above example produces the output shown in Figure 1.
055 * If the container's <code>ComponentOrientation</code> property is horizontal
056 * and right-to-left, the example produces the output shown in Figure 2.
057 * <p>
058 * <center><table COLS=2 WIDTH=600 summary="layout">
059 * <tr ALIGN=CENTER>
060 * <td><img SRC="doc-files/GridLayout-1.gif"
061 * alt="Shows 6 buttons in rows of 2. Row 1 shows buttons 1 then 2.
062 * Row 2 shows buttons 3 then 4. Row 3 shows buttons 5 then 6.">
063 * </td>
064 *
065 * <td ALIGN=CENTER><img SRC="doc-files/GridLayout-2.gif"
066 * alt="Shows 6 buttons in rows of 2. Row 1 shows buttons 2 then 1.
067 * Row 2 shows buttons 4 then 3. Row 3 shows buttons 6 then 5.">
068 * </td>
069 * </tr>
070 *
071 * <tr ALIGN=CENTER>
072 * <td>Figure 1: Horizontal, Left-to-Right</td>
073 *
074 * <td>Figure 2: Horizontal, Right-to-Left</td>
075 * </tr>
076 * </table></center>
077 * <p>
078 * When both the number of rows and the number of columns have
079 * been set to non-zero values, either by a constructor or
080 * by the <tt>setRows</tt> and <tt>setColumns</tt> methods, the number of
081 * columns specified is ignored. Instead, the number of
082 * columns is determined from the specified number of rows
083 * and the total number of components in the layout. So, for
084 * example, if three rows and two columns have been specified
085 * and nine components are added to the layout, they will
086 * be displayed as three rows of three columns. Specifying
087 * the number of columns affects the layout only when the
088 * number of rows is set to zero.
089 *
090 * @version 1.49, 05/05/07
091 * @author Arthur van Hoff
092 * @since JDK1.0
093 */
094 public class GridLayout implements LayoutManager, java.io.Serializable {
095 /*
096 * serialVersionUID
097 */
098 private static final long serialVersionUID = -7411804673224730901L;
099
100 /**
101 * This is the horizontal gap (in pixels) which specifies the space
102 * between columns. They can be changed at any time.
103 * This should be a non-negative integer.
104 *
105 * @serial
106 * @see #getHgap()
107 * @see #setHgap(int)
108 */
109 int hgap;
110 /**
111 * This is the vertical gap (in pixels) which specifies the space
112 * between rows. They can be changed at any time.
113 * This should be a non negative integer.
114 *
115 * @serial
116 * @see #getVgap()
117 * @see #setVgap(int)
118 */
119 int vgap;
120 /**
121 * This is the number of rows specified for the grid. The number
122 * of rows can be changed at any time.
123 * This should be a non negative integer, where '0' means
124 * 'any number' meaning that the number of Rows in that
125 * dimension depends on the other dimension.
126 *
127 * @serial
128 * @see #getRows()
129 * @see #setRows(int)
130 */
131 int rows;
132 /**
133 * This is the number of columns specified for the grid. The number
134 * of columns can be changed at any time.
135 * This should be a non negative integer, where '0' means
136 * 'any number' meaning that the number of Columns in that
137 * dimension depends on the other dimension.
138 *
139 * @serial
140 * @see #getColumns()
141 * @see #setColumns(int)
142 */
143 int cols;
144
145 /**
146 * Creates a grid layout with a default of one column per component,
147 * in a single row.
148 * @since JDK1.1
149 */
150 public GridLayout() {
151 this (1, 0, 0, 0);
152 }
153
154 /**
155 * Creates a grid layout with the specified number of rows and
156 * columns. All components in the layout are given equal size.
157 * <p>
158 * One, but not both, of <code>rows</code> and <code>cols</code> can
159 * be zero, which means that any number of objects can be placed in a
160 * row or in a column.
161 * @param rows the rows, with the value zero meaning
162 * any number of rows.
163 * @param cols the columns, with the value zero meaning
164 * any number of columns.
165 */
166 public GridLayout(int rows, int cols) {
167 this (rows, cols, 0, 0);
168 }
169
170 /**
171 * Creates a grid layout with the specified number of rows and
172 * columns. All components in the layout are given equal size.
173 * <p>
174 * In addition, the horizontal and vertical gaps are set to the
175 * specified values. Horizontal gaps are placed between each
176 * of the columns. Vertical gaps are placed between each of
177 * the rows.
178 * <p>
179 * One, but not both, of <code>rows</code> and <code>cols</code> can
180 * be zero, which means that any number of objects can be placed in a
181 * row or in a column.
182 * <p>
183 * All <code>GridLayout</code> constructors defer to this one.
184 * @param rows the rows, with the value zero meaning
185 * any number of rows
186 * @param cols the columns, with the value zero meaning
187 * any number of columns
188 * @param hgap the horizontal gap
189 * @param vgap the vertical gap
190 * @exception IllegalArgumentException if the value of both
191 * <code>rows</code> and <code>cols</code> is
192 * set to zero
193 */
194 public GridLayout(int rows, int cols, int hgap, int vgap) {
195 if ((rows == 0) && (cols == 0)) {
196 throw new IllegalArgumentException(
197 "rows and cols cannot both be zero");
198 }
199 this .rows = rows;
200 this .cols = cols;
201 this .hgap = hgap;
202 this .vgap = vgap;
203 }
204
205 /**
206 * Gets the number of rows in this layout.
207 * @return the number of rows in this layout
208 * @since JDK1.1
209 */
210 public int getRows() {
211 return rows;
212 }
213
214 /**
215 * Sets the number of rows in this layout to the specified value.
216 * @param rows the number of rows in this layout
217 * @exception IllegalArgumentException if the value of both
218 * <code>rows</code> and <code>cols</code> is set to zero
219 * @since JDK1.1
220 */
221 public void setRows(int rows) {
222 if ((rows == 0) && (this .cols == 0)) {
223 throw new IllegalArgumentException(
224 "rows and cols cannot both be zero");
225 }
226 this .rows = rows;
227 }
228
229 /**
230 * Gets the number of columns in this layout.
231 * @return the number of columns in this layout
232 * @since JDK1.1
233 */
234 public int getColumns() {
235 return cols;
236 }
237
238 /**
239 * Sets the number of columns in this layout to the specified value.
240 * Setting the number of columns has no affect on the layout
241 * if the number of rows specified by a constructor or by
242 * the <tt>setRows</tt> method is non-zero. In that case, the number
243 * of columns displayed in the layout is determined by the total
244 * number of components and the number of rows specified.
245 * @param cols the number of columns in this layout
246 * @exception IllegalArgumentException if the value of both
247 * <code>rows</code> and <code>cols</code> is set to zero
248 * @since JDK1.1
249 */
250 public void setColumns(int cols) {
251 if ((cols == 0) && (this .rows == 0)) {
252 throw new IllegalArgumentException(
253 "rows and cols cannot both be zero");
254 }
255 this .cols = cols;
256 }
257
258 /**
259 * Gets the horizontal gap between components.
260 * @return the horizontal gap between components
261 * @since JDK1.1
262 */
263 public int getHgap() {
264 return hgap;
265 }
266
267 /**
268 * Sets the horizontal gap between components to the specified value.
269 * @param hgap the horizontal gap between components
270 * @since JDK1.1
271 */
272 public void setHgap(int hgap) {
273 this .hgap = hgap;
274 }
275
276 /**
277 * Gets the vertical gap between components.
278 * @return the vertical gap between components
279 * @since JDK1.1
280 */
281 public int getVgap() {
282 return vgap;
283 }
284
285 /**
286 * Sets the vertical gap between components to the specified value.
287 * @param vgap the vertical gap between components
288 * @since JDK1.1
289 */
290 public void setVgap(int vgap) {
291 this .vgap = vgap;
292 }
293
294 /**
295 * Adds the specified component with the specified name to the layout.
296 * @param name the name of the component
297 * @param comp the component to be added
298 */
299 public void addLayoutComponent(String name, Component comp) {
300 }
301
302 /**
303 * Removes the specified component from the layout.
304 * @param comp the component to be removed
305 */
306 public void removeLayoutComponent(Component comp) {
307 }
308
309 /**
310 * Determines the preferred size of the container argument using
311 * this grid layout.
312 * <p>
313 * The preferred width of a grid layout is the largest preferred
314 * width of all of the components in the container times the number of
315 * columns, plus the horizontal padding times the number of columns
316 * minus one, plus the left and right insets of the target container.
317 * <p>
318 * The preferred height of a grid layout is the largest preferred
319 * height of all of the components in the container times the number of
320 * rows, plus the vertical padding times the number of rows minus one,
321 * plus the top and bottom insets of the target container.
322 *
323 * @param parent the container in which to do the layout
324 * @return the preferred dimensions to lay out the
325 * subcomponents of the specified container
326 * @see java.awt.GridLayout#minimumLayoutSize
327 * @see java.awt.Container#getPreferredSize()
328 */
329 public Dimension preferredLayoutSize(Container parent) {
330 synchronized (parent.getTreeLock()) {
331 Insets insets = parent.getInsets();
332 int ncomponents = parent.getComponentCount();
333 int nrows = rows;
334 int ncols = cols;
335
336 if (nrows > 0) {
337 ncols = (ncomponents + nrows - 1) / nrows;
338 } else {
339 nrows = (ncomponents + ncols - 1) / ncols;
340 }
341 int w = 0;
342 int h = 0;
343 for (int i = 0; i < ncomponents; i++) {
344 Component comp = parent.getComponent(i);
345 Dimension d = comp.getPreferredSize();
346 if (w < d.width) {
347 w = d.width;
348 }
349 if (h < d.height) {
350 h = d.height;
351 }
352 }
353 return new Dimension(insets.left + insets.right + ncols * w
354 + (ncols - 1) * hgap, insets.top + insets.bottom
355 + nrows * h + (nrows - 1) * vgap);
356 }
357 }
358
359 /**
360 * Determines the minimum size of the container argument using this
361 * grid layout.
362 * <p>
363 * The minimum width of a grid layout is the largest minimum width
364 * of all of the components in the container times the number of columns,
365 * plus the horizontal padding times the number of columns minus one,
366 * plus the left and right insets of the target container.
367 * <p>
368 * The minimum height of a grid layout is the largest minimum height
369 * of all of the components in the container times the number of rows,
370 * plus the vertical padding times the number of rows minus one, plus
371 * the top and bottom insets of the target container.
372 *
373 * @param parent the container in which to do the layout
374 * @return the minimum dimensions needed to lay out the
375 * subcomponents of the specified container
376 * @see java.awt.GridLayout#preferredLayoutSize
377 * @see java.awt.Container#doLayout
378 */
379 public Dimension minimumLayoutSize(Container parent) {
380 synchronized (parent.getTreeLock()) {
381 Insets insets = parent.getInsets();
382 int ncomponents = parent.getComponentCount();
383 int nrows = rows;
384 int ncols = cols;
385
386 if (nrows > 0) {
387 ncols = (ncomponents + nrows - 1) / nrows;
388 } else {
389 nrows = (ncomponents + ncols - 1) / ncols;
390 }
391 int w = 0;
392 int h = 0;
393 for (int i = 0; i < ncomponents; i++) {
394 Component comp = parent.getComponent(i);
395 Dimension d = comp.getMinimumSize();
396 if (w < d.width) {
397 w = d.width;
398 }
399 if (h < d.height) {
400 h = d.height;
401 }
402 }
403 return new Dimension(insets.left + insets.right + ncols * w
404 + (ncols - 1) * hgap, insets.top + insets.bottom
405 + nrows * h + (nrows - 1) * vgap);
406 }
407 }
408
409 /**
410 * Lays out the specified container using this layout.
411 * <p>
412 * This method reshapes the components in the specified target
413 * container in order to satisfy the constraints of the
414 * <code>GridLayout</code> object.
415 * <p>
416 * The grid layout manager determines the size of individual
417 * components by dividing the free space in the container into
418 * equal-sized portions according to the number of rows and columns
419 * in the layout. The container's free space equals the container's
420 * size minus any insets and any specified horizontal or vertical
421 * gap. All components in a grid layout are given the same size.
422 *
423 * @param parent the container in which to do the layout
424 * @see java.awt.Container
425 * @see java.awt.Container#doLayout
426 */
427 public void layoutContainer(Container parent) {
428 synchronized (parent.getTreeLock()) {
429 Insets insets = parent.getInsets();
430 int ncomponents = parent.getComponentCount();
431 int nrows = rows;
432 int ncols = cols;
433 boolean ltr = parent.getComponentOrientation()
434 .isLeftToRight();
435
436 if (ncomponents == 0) {
437 return;
438 }
439 if (nrows > 0) {
440 ncols = (ncomponents + nrows - 1) / nrows;
441 } else {
442 nrows = (ncomponents + ncols - 1) / ncols;
443 }
444 // 4370316. To position components in the center we should:
445 // 1. get an amount of extra space within Container
446 // 2. incorporate half of that value to the left/top position
447 // Note that we use trancating division for widthOnComponent
448 // The reminder goes to extraWidthAvailable
449 int totalGapsWidth = (ncols - 1) * hgap;
450 int widthWOInsets = parent.width
451 - (insets.left + insets.right);
452 int widthOnComponent = (widthWOInsets - totalGapsWidth)
453 / ncols;
454 int extraWidthAvailable = (widthWOInsets - (widthOnComponent
455 * ncols + totalGapsWidth)) / 2;
456
457 int totalGapsHeight = (nrows - 1) * vgap;
458 int heightWOInsets = parent.height
459 - (insets.top + insets.bottom);
460 int heightOnComponent = (heightWOInsets - totalGapsHeight)
461 / nrows;
462 int extraHeightAvailable = (heightWOInsets - (heightOnComponent
463 * nrows + totalGapsHeight)) / 2;
464 if (ltr) {
465 for (int c = 0, x = insets.left + extraWidthAvailable; c < ncols; c++, x += widthOnComponent
466 + hgap) {
467 for (int r = 0, y = insets.top
468 + extraHeightAvailable; r < nrows; r++, y += heightOnComponent
469 + vgap) {
470 int i = r * ncols + c;
471 if (i < ncomponents) {
472 parent.getComponent(i)
473 .setBounds(x, y, widthOnComponent,
474 heightOnComponent);
475 }
476 }
477 }
478 } else {
479 for (int c = 0, x = (parent.width - insets.right - widthOnComponent)
480 - extraWidthAvailable; c < ncols; c++, x -= widthOnComponent
481 + hgap) {
482 for (int r = 0, y = insets.top
483 + extraHeightAvailable; r < nrows; r++, y += heightOnComponent
484 + vgap) {
485 int i = r * ncols + c;
486 if (i < ncomponents) {
487 parent.getComponent(i)
488 .setBounds(x, y, widthOnComponent,
489 heightOnComponent);
490 }
491 }
492 }
493 }
494 }
495 }
496
497 /**
498 * Returns the string representation of this grid layout's values.
499 * @return a string representation of this grid layout
500 */
501 public String toString() {
502 return getClass().getName() + "[hgap=" + hgap + ",vgap=" + vgap
503 + ",rows=" + rows + ",cols=" + cols + "]";
504 }
505 }
|