001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: */
017: /**
018: * @author Michael Danilov
019: * @version $Revision$
020: */package java.awt;
021:
022: import java.io.Serializable;
023:
024: import org.apache.harmony.awt.internal.nls.Messages;
025:
026: public class GridLayout implements LayoutManager, Serializable {
027: private static final long serialVersionUID = -7411804673224730901L;
028:
029: private static final int DEFAULT_GAP = 0;
030: private static final int DEFAULT_COLS_NUMBER = 0;
031: private static final int DEFAULT_ROWS_NUMBER = 1;
032:
033: private final Toolkit toolkit = Toolkit.getDefaultToolkit();
034:
035: private int rows;
036: private int columns;
037: private int vGap;
038: private int hGap;
039:
040: private transient Component[] components;
041:
042: public GridLayout() {
043: this (DEFAULT_ROWS_NUMBER, DEFAULT_COLS_NUMBER, DEFAULT_GAP,
044: DEFAULT_GAP);
045: toolkit.lockAWT();
046: try {
047: } finally {
048: toolkit.unlockAWT();
049: }
050: }
051:
052: public GridLayout(int rows, int cols) {
053: this (rows, cols, DEFAULT_GAP, DEFAULT_GAP);
054: toolkit.lockAWT();
055: try {
056: } finally {
057: toolkit.unlockAWT();
058: }
059: }
060:
061: public GridLayout(int rows, int cols, int hgap, int vgap) {
062: toolkit.lockAWT();
063: try {
064: if ((rows == 0) && (cols == 0)) {
065: // awt.75=rows and cols cannot both be zero
066: throw new IllegalArgumentException(Messages
067: .getString("awt.75")); //$NON-NLS-1$
068: }
069: // awt.76=rows and cols cannot be negative
070: assert (cols >= 0) && (rows >= 0) : Messages
071: .getString("awt.76"); //$NON-NLS-1$
072:
073: this .rows = rows;
074: columns = cols;
075: vGap = vgap;
076: hGap = hgap;
077:
078: } finally {
079: toolkit.unlockAWT();
080: }
081: }
082:
083: @Override
084: public String toString() {
085: /* The format is based on 1.5 release behavior
086: * which can be revealed by the following code:
087: * System.out.println(new GridLayout());
088: */
089:
090: toolkit.lockAWT();
091: try {
092: return (getClass().getName()
093: + "[hgap=" + hGap + ",vgap=" + vGap //$NON-NLS-1$ //$NON-NLS-2$
094: + ",rows=" + rows + ",cols=" + columns + "]"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
095: } finally {
096: toolkit.unlockAWT();
097: }
098: }
099:
100: public int getHgap() {
101: toolkit.lockAWT();
102: try {
103: return hGap;
104: } finally {
105: toolkit.unlockAWT();
106: }
107: }
108:
109: public int getVgap() {
110: toolkit.lockAWT();
111: try {
112: return vGap;
113: } finally {
114: toolkit.unlockAWT();
115: }
116: }
117:
118: public void setHgap(int hgap) {
119: toolkit.lockAWT();
120: try {
121: hGap = hgap;
122: } finally {
123: toolkit.unlockAWT();
124: }
125: }
126:
127: public void setVgap(int vgap) {
128: toolkit.lockAWT();
129: try {
130: vGap = vgap;
131: } finally {
132: toolkit.unlockAWT();
133: }
134: }
135:
136: public int getColumns() {
137: toolkit.lockAWT();
138: try {
139: return columns;
140: } finally {
141: toolkit.unlockAWT();
142: }
143: }
144:
145: public int getRows() {
146: toolkit.lockAWT();
147: try {
148: return rows;
149: } finally {
150: toolkit.unlockAWT();
151: }
152: }
153:
154: public void setColumns(int cols) {
155: toolkit.lockAWT();
156: try {
157: if ((rows == 0) && (cols == 0)) {
158: // awt.75=rows and cols cannot both be zero
159: throw new IllegalArgumentException(Messages
160: .getString("awt.75")); //$NON-NLS-1$
161: }
162:
163: columns = cols;
164: } finally {
165: toolkit.unlockAWT();
166: }
167: }
168:
169: public void setRows(int rows) {
170: toolkit.lockAWT();
171: try {
172: if ((rows == 0) && (columns == 0)) {
173: // awt.75=rows and cols cannot both be zero
174: throw new IllegalArgumentException(Messages
175: .getString("awt.75")); //$NON-NLS-1$
176: }
177:
178: this .rows = rows;
179: } finally {
180: toolkit.unlockAWT();
181: }
182: }
183:
184: public void addLayoutComponent(String name, Component comp) {
185: // take no action
186: }
187:
188: public void removeLayoutComponent(Component comp) {
189: // take no action
190: }
191:
192: public void layoutContainer(Container parent) {
193: toolkit.lockAWT();
194: try {
195: components = parent.getComponents();
196: if (components.length == 0) {
197: return;
198: }
199: Rectangle clientRect = parent.getClient();
200: if (clientRect.isEmpty()) {
201: return;
202: }
203:
204: Dimension gridSize = calculateGrid();
205:
206: fillGrid(gridSize.width, gridSize.height, clientRect,
207: parent.getComponentOrientation().isLeftToRight());
208: } finally {
209: toolkit.unlockAWT();
210: }
211: }
212:
213: public Dimension minimumLayoutSize(Container parent) {
214: toolkit.lockAWT();
215: try {
216: return parent.addInsets(layoutSize(parent, false));
217: } finally {
218: toolkit.unlockAWT();
219: }
220: }
221:
222: public Dimension preferredLayoutSize(Container parent) {
223: toolkit.lockAWT();
224: try {
225: return parent.addInsets(layoutSize(parent, true));
226: } finally {
227: toolkit.unlockAWT();
228: }
229: }
230:
231: /**
232: * Calculates real grid size from size given in constructor
233: * @return true number of columns, rows in grid
234: */
235: private Dimension calculateGrid() {
236: int trueCols = Math.max(0, columns);
237: int trueRows = Math.max(0, rows);
238:
239: if (trueRows == 0) {
240: trueCols = columns;
241: // trueRows = (int) Math.ceil((double) components.length/(double) trueCols);
242: trueRows = components.length / trueCols;
243: if (components.length % trueCols > 0) {
244: trueRows++;
245: }
246: } else {
247: trueRows = rows;
248: // trueCols = (int) Math.ceil((double) components.length/(double) trueRows);
249: trueCols = components.length / trueRows;
250: if (components.length % trueRows > 0) {
251: trueCols++;
252: }
253: }
254:
255: return new Dimension(trueCols, trueRows);
256: }
257:
258: /**
259: * Calculates & sets components bounds
260: * @param trueCols number of columns in grid
261: * @param trueRows number of rows in grid
262: * @param clientRect rectangle to fit components into
263: * @param l2r true if component orientation is left to right,
264: * false otherwise
265: */
266: private void fillGrid(int trueCols, int trueRows,
267: Rectangle clientRect, boolean l2r) {
268: int colsWidths[] = new int[trueCols];
269: int colsOffsets[] = new int[trueCols];
270: int rowsHeights[] = new int[trueRows];
271: int rowsOffsets[] = new int[trueRows];
272:
273: spreadLength(clientRect.width, clientRect.x, hGap, colsWidths,
274: colsOffsets);
275: spreadLength(clientRect.height, clientRect.y, vGap,
276: rowsHeights, rowsOffsets);
277:
278: exit: for (int i = 0, n = 0; i < trueRows; i++) {
279: for (int j = 0; j < trueCols; j++) {
280: int trueCol = (l2r ? j : trueCols - j - 1);
281:
282: components[n].setBounds(colsOffsets[trueCol],
283: rowsOffsets[i], colsWidths[trueCol],
284: rowsHeights[i]);
285:
286: if (++n == components.length) {
287: break exit;
288: }
289: }
290: }
291: }
292:
293: /**
294: * Computes & sets lengths & offsets of grid rows/columns
295: * @param length size of space to be distributed between rows/columns
296: * @param offset starting coordinate
297: * @param gap gap between each of the rows/columns
298: * @param lengths array of lengths of rows/columns to be set(out parameter)
299: * @param offsets array of offsets of rows/columns to be set(out parameter)
300: */
301: private void spreadLength(int length, int offset, int gap,
302: int lengths[], int offsets[]) {
303: int n = lengths.length;
304: int clearLength = length - (n - 1) * gap;
305:
306: for (int i = 0, sharedLength = 0, accumGap = offset; i < n; i++, accumGap += gap) {
307: int curLength;
308:
309: curLength = (int) (clearLength * ((double) (i + 1) / (double) n))
310: - sharedLength;
311: lengths[i] = curLength;
312: offsets[i] = sharedLength + accumGap;
313: sharedLength += curLength;
314: }
315: }
316:
317: /**
318: * Computes size necessary to layout all
319: * components in container. Insets are not taken into account.
320: * @param container in which to do the layout
321: * @param preferred layout size is determined with components
322: * having preffered sizes if true, minimum sizes otherwise
323: * @return layout dimensions
324: */
325: private Dimension layoutSize(Container parent, boolean preferred) {
326: components = parent.getComponents();
327: if (components.length == 0) {
328: return new Dimension();
329: }
330: Dimension gridSize = calculateGrid();
331: int maxWidth = 0;
332: int maxHeight = 0;
333:
334: for (Component element : components) {
335: Dimension compSize = (preferred ? element
336: .getPreferredSize() : element.getMinimumSize());
337:
338: maxWidth = Math.max(maxWidth, compSize.width);
339: maxHeight = Math.max(maxHeight, compSize.height);
340: }
341:
342: int width = maxWidth * gridSize.width + hGap
343: * (gridSize.width - 1);
344: int height = maxHeight * gridSize.height + vGap
345: * (gridSize.height - 1);
346:
347: return new Dimension(width, height);
348: }
349:
350: }
|