blob: d7512af0a5c4f790d01502d5befd243156a1f6fe [file] [log] [blame]
J. Duke319a3b92007-12-01 00:00:00 +00001/*
2 * Copyright 1995-2006 Sun Microsystems, Inc. All Rights Reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation. Sun designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Sun in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
22 * CA 95054 USA or visit www.sun.com if you need additional information or
23 * have any questions.
24 */
25
26package java.awt;
27
28/**
29 * The <code>GridLayout</code> class is a layout manager that
30 * lays out a container's components in a rectangular grid.
31 * The container is divided into equal-sized rectangles,
32 * and one component is placed in each rectangle.
33 * For example, the following is an applet that lays out six buttons
34 * into three rows and two columns:
35 * <p>
36 * <hr><blockquote>
37 * <pre>
38 * import java.awt.*;
39 * import java.applet.Applet;
40 * public class ButtonGrid extends Applet {
41 * public void init() {
42 * setLayout(new GridLayout(3,2));
43 * add(new Button("1"));
44 * add(new Button("2"));
45 * add(new Button("3"));
46 * add(new Button("4"));
47 * add(new Button("5"));
48 * add(new Button("6"));
49 * }
50 * }
51 * </pre></blockquote><hr>
52 * <p>
53 * If the container's <code>ComponentOrientation</code> property is horizontal
54 * and left-to-right, the above example produces the output shown in Figure 1.
55 * If the container's <code>ComponentOrientation</code> property is horizontal
56 * and right-to-left, the example produces the output shown in Figure 2.
57 * <p>
58 * <center><table COLS=2 WIDTH=600 summary="layout">
59 * <tr ALIGN=CENTER>
60 * <td><img SRC="doc-files/GridLayout-1.gif"
61 * alt="Shows 6 buttons in rows of 2. Row 1 shows buttons 1 then 2.
62 * Row 2 shows buttons 3 then 4. Row 3 shows buttons 5 then 6.">
63 * </td>
64 *
65 * <td ALIGN=CENTER><img SRC="doc-files/GridLayout-2.gif"
66 * alt="Shows 6 buttons in rows of 2. Row 1 shows buttons 2 then 1.
67 * Row 2 shows buttons 4 then 3. Row 3 shows buttons 6 then 5.">
68 * </td>
69 * </tr>
70 *
71 * <tr ALIGN=CENTER>
72 * <td>Figure 1: Horizontal, Left-to-Right</td>
73 *
74 * <td>Figure 2: Horizontal, Right-to-Left</td>
75 * </tr>
76 * </table></center>
77 * <p>
78 * When both the number of rows and the number of columns have
79 * been set to non-zero values, either by a constructor or
80 * by the <tt>setRows</tt> and <tt>setColumns</tt> methods, the number of
81 * columns specified is ignored. Instead, the number of
82 * columns is determined from the specified number of rows
83 * and the total number of components in the layout. So, for
84 * example, if three rows and two columns have been specified
85 * and nine components are added to the layout, they will
86 * be displayed as three rows of three columns. Specifying
87 * the number of columns affects the layout only when the
88 * number of rows is set to zero.
89 *
90 * @author Arthur van Hoff
91 * @since JDK1.0
92 */
93public class GridLayout implements LayoutManager, java.io.Serializable {
94 /*
95 * serialVersionUID
96 */
97 private static final long serialVersionUID = -7411804673224730901L;
98
99 /**
100 * This is the horizontal gap (in pixels) which specifies the space
101 * between columns. They can be changed at any time.
102 * This should be a non-negative integer.
103 *
104 * @serial
105 * @see #getHgap()
106 * @see #setHgap(int)
107 */
108 int hgap;
109 /**
110 * This is the vertical gap (in pixels) which specifies the space
111 * between rows. They can be changed at any time.
112 * This should be a non negative integer.
113 *
114 * @serial
115 * @see #getVgap()
116 * @see #setVgap(int)
117 */
118 int vgap;
119 /**
120 * This is the number of rows specified for the grid. The number
121 * of rows can be changed at any time.
122 * This should be a non negative integer, where '0' means
123 * 'any number' meaning that the number of Rows in that
124 * dimension depends on the other dimension.
125 *
126 * @serial
127 * @see #getRows()
128 * @see #setRows(int)
129 */
130 int rows;
131 /**
132 * This is the number of columns specified for the grid. The number
133 * of columns can be changed at any time.
134 * This should be a non negative integer, where '0' means
135 * 'any number' meaning that the number of Columns in that
136 * dimension depends on the other dimension.
137 *
138 * @serial
139 * @see #getColumns()
140 * @see #setColumns(int)
141 */
142 int cols;
143
144 /**
145 * Creates a grid layout with a default of one column per component,
146 * in a single row.
147 * @since JDK1.1
148 */
149 public GridLayout() {
150 this(1, 0, 0, 0);
151 }
152
153 /**
154 * Creates a grid layout with the specified number of rows and
155 * columns. All components in the layout are given equal size.
156 * <p>
157 * One, but not both, of <code>rows</code> and <code>cols</code> can
158 * be zero, which means that any number of objects can be placed in a
159 * row or in a column.
160 * @param rows the rows, with the value zero meaning
161 * any number of rows.
162 * @param cols the columns, with the value zero meaning
163 * any number of columns.
164 */
165 public GridLayout(int rows, int cols) {
166 this(rows, cols, 0, 0);
167 }
168
169 /**
170 * Creates a grid layout with the specified number of rows and
171 * columns. All components in the layout are given equal size.
172 * <p>
173 * In addition, the horizontal and vertical gaps are set to the
174 * specified values. Horizontal gaps are placed between each
175 * of the columns. Vertical gaps are placed between each of
176 * the rows.
177 * <p>
178 * One, but not both, of <code>rows</code> and <code>cols</code> can
179 * be zero, which means that any number of objects can be placed in a
180 * row or in a column.
181 * <p>
182 * All <code>GridLayout</code> constructors defer to this one.
183 * @param rows the rows, with the value zero meaning
184 * any number of rows
185 * @param cols the columns, with the value zero meaning
186 * any number of columns
187 * @param hgap the horizontal gap
188 * @param vgap the vertical gap
189 * @exception IllegalArgumentException if the value of both
190 * <code>rows</code> and <code>cols</code> is
191 * set to zero
192 */
193 public GridLayout(int rows, int cols, int hgap, int vgap) {
194 if ((rows == 0) && (cols == 0)) {
195 throw new IllegalArgumentException("rows and cols cannot both be zero");
196 }
197 this.rows = rows;
198 this.cols = cols;
199 this.hgap = hgap;
200 this.vgap = vgap;
201 }
202
203 /**
204 * Gets the number of rows in this layout.
205 * @return the number of rows in this layout
206 * @since JDK1.1
207 */
208 public int getRows() {
209 return rows;
210 }
211
212 /**
213 * Sets the number of rows in this layout to the specified value.
214 * @param rows the number of rows in this layout
215 * @exception IllegalArgumentException if the value of both
216 * <code>rows</code> and <code>cols</code> is set to zero
217 * @since JDK1.1
218 */
219 public void setRows(int rows) {
220 if ((rows == 0) && (this.cols == 0)) {
221 throw new IllegalArgumentException("rows and cols cannot both be zero");
222 }
223 this.rows = rows;
224 }
225
226 /**
227 * Gets the number of columns in this layout.
228 * @return the number of columns in this layout
229 * @since JDK1.1
230 */
231 public int getColumns() {
232 return cols;
233 }
234
235 /**
236 * Sets the number of columns in this layout to the specified value.
237 * Setting the number of columns has no affect on the layout
238 * if the number of rows specified by a constructor or by
239 * the <tt>setRows</tt> method is non-zero. In that case, the number
240 * of columns displayed in the layout is determined by the total
241 * number of components and the number of rows specified.
242 * @param cols the number of columns in this layout
243 * @exception IllegalArgumentException if the value of both
244 * <code>rows</code> and <code>cols</code> is set to zero
245 * @since JDK1.1
246 */
247 public void setColumns(int cols) {
248 if ((cols == 0) && (this.rows == 0)) {
249 throw new IllegalArgumentException("rows and cols cannot both be zero");
250 }
251 this.cols = cols;
252 }
253
254 /**
255 * Gets the horizontal gap between components.
256 * @return the horizontal gap between components
257 * @since JDK1.1
258 */
259 public int getHgap() {
260 return hgap;
261 }
262
263 /**
264 * Sets the horizontal gap between components to the specified value.
265 * @param hgap the horizontal gap between components
266 * @since JDK1.1
267 */
268 public void setHgap(int hgap) {
269 this.hgap = hgap;
270 }
271
272 /**
273 * Gets the vertical gap between components.
274 * @return the vertical gap between components
275 * @since JDK1.1
276 */
277 public int getVgap() {
278 return vgap;
279 }
280
281 /**
282 * Sets the vertical gap between components to the specified value.
283 * @param vgap the vertical gap between components
284 * @since JDK1.1
285 */
286 public void setVgap(int vgap) {
287 this.vgap = vgap;
288 }
289
290 /**
291 * Adds the specified component with the specified name to the layout.
292 * @param name the name of the component
293 * @param comp the component to be added
294 */
295 public void addLayoutComponent(String name, Component comp) {
296 }
297
298 /**
299 * Removes the specified component from the layout.
300 * @param comp the component to be removed
301 */
302 public void removeLayoutComponent(Component comp) {
303 }
304
305 /**
306 * Determines the preferred size of the container argument using
307 * this grid layout.
308 * <p>
309 * The preferred width of a grid layout is the largest preferred
310 * width of all of the components in the container times the number of
311 * columns, plus the horizontal padding times the number of columns
312 * minus one, plus the left and right insets of the target container.
313 * <p>
314 * The preferred height of a grid layout is the largest preferred
315 * height of all of the components in the container times the number of
316 * rows, plus the vertical padding times the number of rows minus one,
317 * plus the top and bottom insets of the target container.
318 *
319 * @param parent the container in which to do the layout
320 * @return the preferred dimensions to lay out the
321 * subcomponents of the specified container
322 * @see java.awt.GridLayout#minimumLayoutSize
323 * @see java.awt.Container#getPreferredSize()
324 */
325 public Dimension preferredLayoutSize(Container parent) {
326 synchronized (parent.getTreeLock()) {
327 Insets insets = parent.getInsets();
328 int ncomponents = parent.getComponentCount();
329 int nrows = rows;
330 int ncols = cols;
331
332 if (nrows > 0) {
333 ncols = (ncomponents + nrows - 1) / nrows;
334 } else {
335 nrows = (ncomponents + ncols - 1) / ncols;
336 }
337 int w = 0;
338 int h = 0;
339 for (int i = 0 ; i < ncomponents ; i++) {
340 Component comp = parent.getComponent(i);
341 Dimension d = comp.getPreferredSize();
342 if (w < d.width) {
343 w = d.width;
344 }
345 if (h < d.height) {
346 h = d.height;
347 }
348 }
349 return new Dimension(insets.left + insets.right + ncols*w + (ncols-1)*hgap,
350 insets.top + insets.bottom + nrows*h + (nrows-1)*vgap);
351 }
352 }
353
354 /**
355 * Determines the minimum size of the container argument using this
356 * grid layout.
357 * <p>
358 * The minimum width of a grid layout is the largest minimum width
359 * of all of the components in the container times the number of columns,
360 * plus the horizontal padding times the number of columns minus one,
361 * plus the left and right insets of the target container.
362 * <p>
363 * The minimum height of a grid layout is the largest minimum height
364 * of all of the components in the container times the number of rows,
365 * plus the vertical padding times the number of rows minus one, plus
366 * the top and bottom insets of the target container.
367 *
368 * @param parent the container in which to do the layout
369 * @return the minimum dimensions needed to lay out the
370 * subcomponents of the specified container
371 * @see java.awt.GridLayout#preferredLayoutSize
372 * @see java.awt.Container#doLayout
373 */
374 public Dimension minimumLayoutSize(Container parent) {
375 synchronized (parent.getTreeLock()) {
376 Insets insets = parent.getInsets();
377 int ncomponents = parent.getComponentCount();
378 int nrows = rows;
379 int ncols = cols;
380
381 if (nrows > 0) {
382 ncols = (ncomponents + nrows - 1) / nrows;
383 } else {
384 nrows = (ncomponents + ncols - 1) / ncols;
385 }
386 int w = 0;
387 int h = 0;
388 for (int i = 0 ; i < ncomponents ; i++) {
389 Component comp = parent.getComponent(i);
390 Dimension d = comp.getMinimumSize();
391 if (w < d.width) {
392 w = d.width;
393 }
394 if (h < d.height) {
395 h = d.height;
396 }
397 }
398 return new Dimension(insets.left + insets.right + ncols*w + (ncols-1)*hgap,
399 insets.top + insets.bottom + nrows*h + (nrows-1)*vgap);
400 }
401 }
402
403 /**
404 * Lays out the specified container using this layout.
405 * <p>
406 * This method reshapes the components in the specified target
407 * container in order to satisfy the constraints of the
408 * <code>GridLayout</code> object.
409 * <p>
410 * The grid layout manager determines the size of individual
411 * components by dividing the free space in the container into
412 * equal-sized portions according to the number of rows and columns
413 * in the layout. The container's free space equals the container's
414 * size minus any insets and any specified horizontal or vertical
415 * gap. All components in a grid layout are given the same size.
416 *
417 * @param parent the container in which to do the layout
418 * @see java.awt.Container
419 * @see java.awt.Container#doLayout
420 */
421 public void layoutContainer(Container parent) {
422 synchronized (parent.getTreeLock()) {
423 Insets insets = parent.getInsets();
424 int ncomponents = parent.getComponentCount();
425 int nrows = rows;
426 int ncols = cols;
427 boolean ltr = parent.getComponentOrientation().isLeftToRight();
428
429 if (ncomponents == 0) {
430 return;
431 }
432 if (nrows > 0) {
433 ncols = (ncomponents + nrows - 1) / nrows;
434 } else {
435 nrows = (ncomponents + ncols - 1) / ncols;
436 }
437 // 4370316. To position components in the center we should:
438 // 1. get an amount of extra space within Container
439 // 2. incorporate half of that value to the left/top position
440 // Note that we use trancating division for widthOnComponent
441 // The reminder goes to extraWidthAvailable
442 int totalGapsWidth = (ncols - 1) * hgap;
443 int widthWOInsets = parent.width - (insets.left + insets.right);
444 int widthOnComponent = (widthWOInsets - totalGapsWidth) / ncols;
445 int extraWidthAvailable = (widthWOInsets - (widthOnComponent * ncols + totalGapsWidth)) / 2;
446
447 int totalGapsHeight = (nrows - 1) * vgap;
448 int heightWOInsets = parent.height - (insets.top + insets.bottom);
449 int heightOnComponent = (heightWOInsets - totalGapsHeight) / nrows;
450 int extraHeightAvailable = (heightWOInsets - (heightOnComponent * nrows + totalGapsHeight)) / 2;
451 if (ltr) {
452 for (int c = 0, x = insets.left + extraWidthAvailable; c < ncols ; c++, x += widthOnComponent + hgap) {
453 for (int r = 0, y = insets.top + extraHeightAvailable; r < nrows ; r++, y += heightOnComponent + vgap) {
454 int i = r * ncols + c;
455 if (i < ncomponents) {
456 parent.getComponent(i).setBounds(x, y, widthOnComponent, heightOnComponent);
457 }
458 }
459 }
460 } else {
461 for (int c = 0, x = (parent.width - insets.right - widthOnComponent) - extraWidthAvailable; c < ncols ; c++, x -= widthOnComponent + hgap) {
462 for (int r = 0, y = insets.top + extraHeightAvailable; r < nrows ; r++, y += heightOnComponent + vgap) {
463 int i = r * ncols + c;
464 if (i < ncomponents) {
465 parent.getComponent(i).setBounds(x, y, widthOnComponent, heightOnComponent);
466 }
467 }
468 }
469 }
470 }
471 }
472
473 /**
474 * Returns the string representation of this grid layout's values.
475 * @return a string representation of this grid layout
476 */
477 public String toString() {
478 return getClass().getName() + "[hgap=" + hgap + ",vgap=" + vgap +
479 ",rows=" + rows + ",cols=" + cols + "]";
480 }
481}