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: }
|