PageRenderTime 110ms CodeModel.GetById 82ms app.highlight 24ms RepoModel.GetById 0ms app.codeStats 1ms

/jEdit/tags/jedit-4-2-pre4/installer/VariableGridLayout.java

#
Java | 334 lines | 183 code | 53 blank | 98 comment | 40 complexity | 39bcb51e0afeb0ff91021f07ddc57984 MD5 | raw file
  1/*
  2 * VariableGridLayout.java - a grid layout manager with variable cell sizes
  3 *
  4 * Originally written by Dirk Moebius for the jEdit project. This work has been
  5 * placed into the public domain. You may use this work in any way and for any
  6 * purpose you wish.
  7 *
  8 * THIS SOFTWARE IS PROVIDED AS-IS WITHOUT WARRANTY OF ANY KIND, NOT EVEN THE
  9 * IMPLIED WARRANTY OF MERCHANTABILITY. THE AUTHOR OF THIS SOFTWARE, ASSUMES
 10 * _NO_ RESPONSIBILITY FOR ANY CONSEQUENCE RESULTING FROM THE USE, MODIFICATION,
 11 * OR REDISTRIBUTION OF THIS SOFTWARE.
 12 */
 13
 14package installer;
 15
 16
 17import java.awt.*;
 18
 19// This is copied from jEdit's org.gjt.sp.jedit.gui package.
 20
 21/**
 22 * The <code>VariableGridLayout</code> class is a layout manager
 23 * that lays out a container's components in a rectangular grid
 24 * with variable cell sizes.<p>
 25 *
 26 * The container is divided into rectangles, and one component is placed
 27 * in each rectangle. Each row is as large as the largest component in
 28 * that row, and each column is as wide as the widest component in
 29 * that column.<p>
 30 *
 31 * This behavior is basically the same as in
 32 * <code>java.awt.GridLayout</code>, but with different row heights and
 33 * column widths for each row/column.<p>
 34 *
 35 * For example, the following is an applet that lays out six buttons
 36 * into three rows and two columns:<p>
 37 *
 38 * <blockquote><pre>
 39 * import java.awt.*;
 40 * import java.applet.Applet;
 41 * public class ButtonGrid extends Applet {
 42 *     public void init() {
 43 *         setLayout(new VariableGridLayout(VariableGridLayout.FIXED_NUM_COLUMNS, 2));
 44 *         add(new Button("1"));
 45 *         add(new Button("2"));
 46 *         add(new Button("3"));
 47 *         add(new Button("4"));
 48 *         add(new Button("5"));
 49 *         add(new Button("6"));
 50 *     }
 51 * }
 52 * </pre></blockquote><p>
 53 *
 54 * <b>Programmer's remark:</b> VariableGridLayout could be faster, if it would
 55 * reside in the package java.awt, because then it could access some
 56 * package private fields of <code>Container</code> or
 57 * <code>Component</code>. Instead, it has to call
 58 * <code>Component.getSize()</code>,
 59 * which allocates memory on the heap.<p>
 60 *
 61 * <b>Todo:</b>
 62 * <ul>
 63 * <li>Use alignmentX/Y property if the grid cell is larger than the preferred size of the component.
 64 * <li>Ability to span components over more than one cell horizontally
 65 * </ul>
 66 *
 67 * @author Dirk Moebius
 68 * @version 1.0
 69 * @see java.awt.GridLayout
 70 */
 71public class VariableGridLayout implements LayoutManager2, java.io.Serializable
 72{
 73
 74	public static final int FIXED_NUM_ROWS = 1;
 75	public static final int FIXED_NUM_COLUMNS = 2;
 76
 77
 78	public VariableGridLayout(int mode, int size, int hgap, int vgap) {
 79		if (mode != FIXED_NUM_ROWS && mode != FIXED_NUM_COLUMNS) {
 80			throw new IllegalArgumentException("illegal mode; value is " + mode);
 81		}
 82		if (size <= 0) {
 83			throw new IllegalArgumentException("size cannot be zero or less; value is " + size);
 84		}
 85		if (hgap < 0) {
 86			throw new IllegalArgumentException("hgap cannot be negative; value is " + hgap);
 87		}
 88		if (vgap < 0) {
 89			throw new IllegalArgumentException("vgap cannot be negative; value is " + vgap);
 90		}
 91		this.mode = mode;
 92		this.size = size;
 93		this.hgap = hgap;
 94		this.vgap = vgap;
 95	}
 96
 97
 98	/**
 99	 * Creates a variable grid layout manager with the specified mode
100	 * and zero horizontal and vertical gap.
101	 */
102	public VariableGridLayout(int mode, int size) {
103		this(mode, size, 0, 0);
104	}
105
106
107	/**
108	 * Creates a variable grid layout manager with mode FIXED_NUM_ROWS,
109	 * number of rows == 1 and zero horizontal and vertical gap.
110	 */
111	public VariableGridLayout() {
112		this(FIXED_NUM_ROWS, 1, 0, 0);
113	}
114
115
116	/**
117	 * Not used in this class.
118	 */
119	public void addLayoutComponent(String name, Component component) { }
120
121
122	/**
123	 * Not used in this class.
124	 */
125	public void addLayoutComponent(Component component, Object constraints) { }
126
127
128	/**
129	 * Not used in this class.
130	 */
131	public void removeLayoutComponent(Component component) { }
132
133
134	/**
135	 * Always returns 0.5.
136	 */
137	public float getLayoutAlignmentX(Container container) {
138		return 0.5f;
139	}
140
141
142	/**
143	 * Always returns 0.5.
144	 */
145	public float getLayoutAlignmentY(Container container) {
146		return 0.5f;
147	}
148
149
150	public Dimension preferredLayoutSize(Container parent) {
151		return getLayoutSize(parent, 2);
152	}
153
154
155	public Dimension minimumLayoutSize(Container parent) {
156		return getLayoutSize(parent, 0);
157	}
158
159
160	public Dimension maximumLayoutSize(Container parent) {
161		return getLayoutSize(parent, 1);
162	}
163
164
165	public void layoutContainer(Container parent) {
166		synchronized (parent.getTreeLock()) {
167			update(parent);
168
169			int ncomponents = parent.getComponentCount();
170
171			if (ncomponents == 0) {
172				return;
173			}
174
175			// Pass 1: compute preferred row heights / column widths
176			int total_height = 0;
177			for (int r = 0, i = 0; r < nrows; r++) {
178				for (int c = 0; c < ncols; c++, i++) {
179					if (i < ncomponents) {
180						Dimension d = parent.getComponent(i).getPreferredSize();
181						row_heights[r] = Math.max(row_heights[r], d.height);
182						col_widths[c] = Math.max(col_widths[c], d.width);
183					} else {
184						break;
185					}
186				}
187				total_height += row_heights[r];
188			}
189
190			int total_width = 0;
191			for (int c = 0; c < ncols; c++) {
192				total_width += col_widths[c];
193			}
194
195			// Pass 2: redistribute free space
196			Dimension parent_size = parent.getSize();
197			Insets insets = parent.getInsets();
198			int free_height = parent_size.height - insets.top - insets.bottom - (nrows - 1) * vgap;
199			int free_width = parent_size.width - insets.left - insets.right - (ncols - 1) * hgap;
200
201			if (total_height != free_height) {
202				double dy = (double)free_height / (double)total_height;
203				for (int r = 0; r < nrows; r++) {
204					row_heights[r] = (int) ((double)row_heights[r] * dy);
205				}
206			}
207
208			if (total_width != free_width) {
209				double dx = ((double)free_width) / ((double)total_width);
210				for (int c = 0; c < ncols; c++) {
211					col_widths[c] = (int) ((double)col_widths[c] * dx);
212				}
213			}
214
215			// Pass 3: layout components
216			for (int r = 0, y = insets.top, i = 0; r < nrows; y += row_heights[r] + vgap, r++) {
217				for (int c = 0, x = insets.left; c < ncols; x += col_widths[c] + hgap, c++, i++) {
218					if (i < ncomponents) {
219						parent.getComponent(i).setBounds(x, y, col_widths[c], row_heights[r]);
220					}
221				}
222			}
223
224		} // synchronized
225	}
226
227
228	public void invalidateLayout(Container container) {}
229
230
231	/**
232	 * Returns the string representation of this variable grid layout's values.
233	 * @return  a string representation of this variable grid layout.
234	 */
235	public String toString() {
236		return getClass().getName() + "[mode=" + mode + ",size=" + size
237			   + ",hgap=" + hgap + ",vgap=" + vgap + "]";
238	}
239
240
241	/**
242	 * @param  which  if 0 compute minimum layout size,
243	 *				if 1 compute maximum layout size,
244	 *				otherwise compute preferred layout size.
245	 */
246	private Dimension getLayoutSize(Container parent, int which) {
247		synchronized (parent.getTreeLock()){
248			update(parent);
249
250			int ncomponents = parent.getComponentCount();
251			int h = 0;
252			int w = 0;
253
254			for (int r = 0, i = 0; r < nrows; r++) {
255				int row_height = 0;
256				for (int c = 0; c < ncols; c++, i++) {
257					if (i < ncomponents) {
258						switch (which) {
259							case 0:
260								row_height = Math.max(row_height, parent.getComponent(i).getMinimumSize().height);
261								break;
262							case 1:
263								row_height = Math.max(row_height, parent.getComponent(i).getMaximumSize().height);
264								break;
265							default:
266								row_height = Math.max(row_height, parent.getComponent(i).getPreferredSize().height);
267								break;
268						}
269					} else {
270						break;
271					}
272				}
273				h += row_height;
274			}
275
276			for (int c = 0; c < ncols; c++) {
277				int col_width = 0;
278				for (int r = 0; r < nrows; r++) {
279					int i = r * ncols + c;
280					if (i < ncomponents) {
281						switch (which) {
282							case 0:
283								col_width = Math.max(col_width, parent.getComponent(i).getMinimumSize().width);
284								break;
285							case 1:
286								col_width = Math.max(col_width, parent.getComponent(i).getMaximumSize().width);
287								break;
288							default:
289								col_width = Math.max(col_width, parent.getComponent(i).getPreferredSize().width);
290								break;
291						}
292					} else {
293						break;
294					}
295				}
296				w += col_width;
297			}
298
299			Insets insets = parent.getInsets();
300			return new Dimension(w + insets.left + insets.right + ((ncols - 1) * hgap),
301								 h + insets.top + insets.bottom + ((nrows - 1) * vgap));
302		}
303	}
304
305
306	private void update(Container container) {
307		int ncomponents = container.getComponentCount();
308		int old_nrows = nrows;
309		int old_ncols = ncols;
310		if (this.mode == FIXED_NUM_ROWS) {
311			nrows = this.size;
312			ncols = (ncomponents + nrows - 1) / nrows;
313		} else {
314			ncols = this.size;
315			nrows = (ncomponents + ncols - 1) / ncols;
316		}
317		if (old_nrows != nrows) {
318			row_heights = new int[nrows];
319		}
320		if (old_ncols != ncols) {
321			col_widths = new int[ncols];
322		}
323	}
324
325
326	private int mode;
327	private int size;
328	private int hgap;
329	private int vgap;
330	private transient int nrows = -1;
331	private transient int ncols = -1;
332	private transient int[] row_heights = null;
333	private transient int[] col_widths = null;
334}